Browse Source

Merge upstream version 4.5.1

Christoph Biedl 4 months ago
parent
commit
f4508d8dc3
100 changed files with 2714 additions and 1309 deletions
  1. 0 303
      INSTALL
  2. 3 4
      Makefile.in
  3. 499 17
      configure
  4. 122 11
      configure.ac
  5. 41 6
      docs/CHANGELOG
  6. 27 0
      docs/CREDIT
  7. 29 0
      docs/INSTALL
  8. 67 44
      lib/sll.h
  9. 1 1
      lib/strlcpy.h
  10. 3 3
      libopts/m4/libopts.m4
  11. 3 3
      src/bridge.c
  12. 1 1
      src/bridge.h
  13. 1 1
      src/common.h
  14. 1 1
      src/common/cache.c
  15. 1 1
      src/common/cache.h
  16. 7 1
      src/common/cidr.c
  17. 1 1
      src/common/cidr.h
  18. 22 0
      src/common/dlt_names.c
  19. 4 0
      src/common/dlt_names.h
  20. 3 1
      src/common/err.c
  21. 9 5
      src/common/err.h
  22. 1 1
      src/common/fakepcap.c
  23. 5 1
      src/common/fakepcap.h
  24. 3 2
      src/common/fakepcapnav.c
  25. 1 1
      src/common/fakepcapnav.h
  26. 69 22
      src/common/flows.c
  27. 3 2
      src/common/flows.h
  28. 135 36
      src/common/get.c
  29. 1 1
      src/common/get.h
  30. 1 1
      src/common/git_version.c
  31. 1 1
      src/common/interface.c
  32. 1 1
      src/common/interface.h
  33. 25 24
      src/common/list.c
  34. 1 1
      src/common/list.h
  35. 1 1
      src/common/mac.c
  36. 1 1
      src/common/mac.h
  37. 1 1
      src/common/pcap_dlt.h
  38. 321 99
      src/common/sendpacket.c
  39. 130 4
      src/common/sendpacket.h
  40. 1 1
      src/common/services.c
  41. 1 1
      src/common/services.h
  42. 2 2
      src/common/tcpdump.c
  43. 1 1
      src/common/tcpdump.h
  44. 17 4
      src/common/timer.c
  45. 30 2
      src/common/timer.h
  46. 23 11
      src/common/utils.c
  47. 8 7
      src/common/utils.h
  48. 1 1
      src/common/xX.c
  49. 1 1
      src/common/xX.h
  50. 33 0
      src/config.h.in
  51. 39 6
      src/defines.h
  52. 39 6
      src/defines.h.in
  53. 1 1
      src/fragroute/fragroute.c
  54. 1 1
      src/fragroute/fragroute.h
  55. 9 9
      src/replay.c
  56. 1 1
      src/replay.h
  57. 253 118
      src/send_packets.c
  58. 12 1
      src/send_packets.h
  59. 1 1
      src/signal_handler.c
  60. 1 1
      src/signal_handler.h
  61. 11 11
      src/sleep.c
  62. 26 17
      src/sleep.h
  63. 16 3
      src/tcpbridge.1
  64. 5 4
      src/tcpbridge.c
  65. 1 1
      src/tcpbridge.h
  66. 420 360
      src/tcpbridge_opts.c
  67. 14 4
      src/tcpbridge_opts.def
  68. 83 73
      src/tcpbridge_opts.h
  69. 1 1
      src/tcpcapinfo.1
  70. 1 1
      src/tcpcapinfo.c
  71. 1 1
      src/tcpcapinfo_opts.c
  72. 2 2
      src/tcpcapinfo_opts.def
  73. 45 3
      src/tcpedit/Makefile.in
  74. 1 1
      src/tcpedit/checksum.c
  75. 1 1
      src/tcpedit/checksum.h
  76. 10 7
      src/tcpedit/dlt.c
  77. 1 1
      src/tcpedit/dlt.h
  78. 8 7
      src/tcpedit/edit_packet.c
  79. 1 1
      src/tcpedit/edit_packet.h
  80. 5 1
      src/tcpedit/parse_args.c
  81. 1 1
      src/tcpedit/parse_args.h
  82. 1 1
      src/tcpedit/plugins.h
  83. 1 0
      src/tcpedit/plugins/Makefile.am
  84. 12 8
      src/tcpedit/plugins/dlt_en10mb/en10mb.c
  85. 1 1
      src/tcpedit/plugins/dlt_en10mb/en10mb.h
  86. 1 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_api.c
  87. 1 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_api.h
  88. 1 1
      src/tcpedit/plugins/dlt_en10mb/en10mb_types.h
  89. 1 1
      src/tcpedit/plugins/dlt_hdlc/hdlc.c
  90. 1 1
      src/tcpedit/plugins/dlt_hdlc/hdlc.h
  91. 1 1
      src/tcpedit/plugins/dlt_hdlc/hdlc_api.c
  92. 1 1
      src/tcpedit/plugins/dlt_hdlc/hdlc_api.h
  93. 1 1
      src/tcpedit/plugins/dlt_hdlc/hdlc_types.h
  94. 1 1
      src/tcpedit/plugins/dlt_ieee80211/ieee80211.c
  95. 1 1
      src/tcpedit/plugins/dlt_ieee80211/ieee80211.h
  96. 1 1
      src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.c
  97. 1 1
      src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.h
  98. 1 1
      src/tcpedit/plugins/dlt_ieee80211/ieee80211_types.h
  99. 11 5
      src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c
  100. 0 0
      src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.h

+ 0 - 303
INSTALL

@@ -1,303 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
-2006, 2014 Free Software Foundation, Inc.
-
-This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-
-Advanced Installation
-=====================
-Visit http://tcpreplay.appneta.com/wiki/installation.html
-
-
-Basic Installation
-==================
-
-    ./configure 
-    make
-    sudo make install
-
-Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package.  The following
-more-detailed instructions are generic; see the `README' file for
-instructions specific to this package.
-
-   The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation.  It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions.  Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
-   It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring.  Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.
-
-   If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release.  If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
-   The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'.  You need `configure.ac' if
-you want to change it or regenerate `configure' using a newer version
-of `autoconf'.
-
-The simplest way to compile this package is:
-
-  1. `cd' to the directory containing the package's source code and type
-     `./configure' to configure the package for your system.
-
-     Running `configure' might take a while.  While running, it prints
-     some messages telling which features it is checking for.
-
-  2. Type `make' to compile the package.
-
-  3. Optionally, type `make check' to run any self-tests that come with
-     the package.
-
-  4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
-     source code directory by typing `make clean'.  To also remove the
-     files that `configure' created (so you can compile the package for
-     a different kind of computer), type `make distclean'.  There is
-     also a `make maintainer-clean' target, but that is intended mainly
-     for the package's developers.  If you use it, you may have to get
-     all sorts of other programs in order to regenerate files that came
-     with the distribution.
-
-
-How to make Tcpreplay go fast
-=============================
-
-1) netmap
-   ------
-This feature will detect netmap capable network drivers on Linux and
-BSD systems. If detected, the network driver is bypassed for the
-execution duration of tcpreplay and tcpreplay-edit, and network buffers
-will be written to directly. This will allow you to achieve full 10GigE
-line rates on commodity 10GigE network adapters, similar to rates 
-achieved by commercial network traffic generators.
-
-Note that bypassing the network driver will disrupt other applications
-connected through the test interface. Use caution when testing on the
-same interface you ssh'ed into.
-
-Ensure that you have supported NICs installed. Most Intel and nForce 
-(nVidia) adapters will work. Some virtual adapters are supported.
-
-FreeBSD 10 and higher already contains netmap capabilities and should
-be detected automatically by "configure". But first you must enable
-netmap on the system by adding 'device netmap' to your kernel config
-and rebuilding the kernel. When complete, /dev/netmap will be
-available.
-
-For Linux, download latest netmap sources from http://info.iet.unipi.it/~luigi/netmap/
-or run 'git clone https://code.google.com/p/netmap/'. You will also need to have 
-kernel sources installed so the build system can patch the sources and build 
-netmap-enabled drivers. If kernel sources are in /a/b/c/linux-A.B.C/ , then you
-should do:
-
-    cd netmap/LINUX
-    make KSRC=/a/b/c/linux-A.B.C/       # builds the kernel modules
-    make KSRC=/a/b/c/linux-A.B.C/ apps  # builds sample applications
-
-You can omit KSRC if your kernel sources are in a standard place.
-
-Once you load the netmap.lin.ko module on your Linux machine, /dev/netmap 
-will be available. You will also need to replace your existing network drivers
-(beyond the scope of this document).
-
-Building netmap-aware Tcpreplay suite is relatively straight forward. For
-FreeBSD, build normally. For Linux, if you extracted netmap into /usr/src/ you 
-can also build normally. Otherwise you will have to specify the netmap source
-directory, for example:
-
-    ./configure --with-netmap=/home/fklassen/git/netmap
-    make
-    sudo make install
-
-
-Compilers and Options
-=====================
-
-Some systems require unusual options for compilation or linking that the
-`configure' script does not know about.  Run `./configure --help' for
-details on some of the pertinent environment variables.
-
-   You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment.  Here
-is an example:
-
-     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
-
-   *Note Defining Variables::, for more details.
-
-
-Compiling For Multiple Architectures
-====================================
-
-You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory.  To do this, you can use GNU `make'.  `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
-   With a non-GNU `make', it is safer to compile the package for one
-architecture at a time in the source code directory.  After you have
-installed the package for one architecture, use `make distclean' before
-reconfiguring for another architecture.
-
-
-Installation Names
-==================
-
-By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc.  You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX'.
-
-   You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files.  If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
-   In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
-   If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-
-Optional Features
-=================
-
-Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System).  The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
-   For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-
-Specifying the System Type
-==========================
-
-There may be some features `configure' cannot figure out automatically,
-but needs to determine by the type of machine the package will run on.
-Usually, assuming the package is built to be run on the _same_
-architectures, `configure' can figure that out, but if it prints a
-message saying it cannot guess the machine type, give it the
-`--build=TYPE' option.  TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
-     CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
-     OS KERNEL-OS
-
-   See the file `config.sub' for the possible values of each field.  If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
-   If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
-
-   If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-
-Sharing Defaults
-================
-
-If you want to set default values for `configure' scripts to share, you
-can create a site shell script called `config.site' that gives default
-values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists.  Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-
-Defining Variables
-==================
-
-Variables not defined in a site shell script can be set in the
-environment passed to `configure'.  However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost.  In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'.  For example:
-
-     ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug.  Until the bug is fixed you can use this workaround:
-
-     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-
-`configure' Invocation
-======================
-
-`configure' recognizes the following options to control how it operates.
-
-`--help'
-`-h'
-     Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
-     Print the version of Autoconf used to generate the `configure'
-     script, and exit.
-
-`--cache-file=FILE'
-     Enable the cache: use and save the results of the tests in FILE,
-     traditionally `config.cache'.  FILE defaults to `/dev/null' to
-     disable caching.
-
-`--config-cache'
-`-C'
-     Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
-     Do not print messages saying which checks are being made.  To
-     suppress all normal output, redirect it to `/dev/null' (any error
-     messages will still be shown).
-
-`--srcdir=DIR'
-     Look for the package's source code in directory DIR.  Usually
-     `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options.  Run
-`configure --help' for more details.
-

+ 3 - 4
Makefile.in

@@ -166,10 +166,9 @@ am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/doxygen.cfg.in \
 	$(top_srcdir)/config/config.guess \
 	$(top_srcdir)/config/config.sub \
 	$(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
-	$(top_srcdir)/config/missing INSTALL config/ar-lib \
-	config/compile config/config.guess config/config.sub \
-	config/depcomp config/install-sh config/ltmain.sh \
-	config/missing
+	$(top_srcdir)/config/missing config/ar-lib config/compile \
+	config/config.guess config/config.sub config/depcomp \
+	config/install-sh config/ltmain.sh config/missing
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)

+ 499 - 17
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for tcpreplay 4.4.4.
+# Generated by GNU Autoconf 2.69 for tcpreplay 4.5.1.
 #
 # Report bugs to <https://github.com/appneta/tcpreplay/issues>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='tcpreplay'
 PACKAGE_TARNAME='tcpreplay'
-PACKAGE_VERSION='4.4.4'
-PACKAGE_STRING='tcpreplay 4.4.4'
+PACKAGE_VERSION='4.5.1'
+PACKAGE_STRING='tcpreplay 4.5.1'
 PACKAGE_BUGREPORT='https://github.com/appneta/tcpreplay/issues'
 PACKAGE_URL='http://tcpreplay.sourceforge.net/'
 
@@ -861,6 +861,7 @@ enable_64bits
 enable_force_bpf
 enable_force_pf
 enable_force_libdnet
+enable_force_libxdp
 enable_force_inject
 enable_force_sendpacket
 enable_static_link
@@ -1447,7 +1448,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures tcpreplay 4.4.4 to adapt to many kinds of systems.
+\`configure' configures tcpreplay 4.5.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1519,7 +1520,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of tcpreplay 4.4.4:";;
+     short | recursive ) echo "Configuration of tcpreplay 4.5.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1560,6 +1561,7 @@ Optional Features:
   --enable-force-bpf      Force using BPF for sending packets
   --enable-force-pf       Force using Linux's PF_PACKET for sending packets
   --enable-force-libdnet  Force using libdnet for sending packets
+  --enable-force-libxdp   Force using libxdp for sending packets
   --enable-force-inject   Force using libpcap's pcap_inject() for sending
                           packets
   --enable-force-sendpacket
@@ -1692,7 +1694,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-tcpreplay configure 4.4.4
+tcpreplay configure 4.5.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2652,7 +2654,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by tcpreplay $as_me 4.4.4, which was
+It was created by tcpreplay $as_me 4.5.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3814,7 +3816,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='tcpreplay'
- VERSION='4.4.4'
+ VERSION='4.5.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -21053,6 +21055,14 @@ $as_echo "#define FORCE_INJECT_LIBDNET 1" >>confdefs.h
 fi
 
 
+# Check whether --enable-force-libxdp was given.
+if test "${enable_force_libxdp+set}" = set; then :
+  enableval=$enable_force_libxdp;
+$as_echo "#define FORCE_INJECT_LIBXDP 1" >>confdefs.h
+
+fi
+
+
 # Check whether --enable-force-inject was given.
 if test "${enable_force_inject+set}" = set; then :
   enableval=$enable_force_inject;
@@ -21112,7 +21122,55 @@ $as_echo "#define HAVE_INET_ATON 1" >>confdefs.h
 
     inet_aton=yes
 else
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_aton in -lnetwork" >&5
+$as_echo_n "checking for inet_aton in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_inet_aton+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inet_aton ();
+int
+main ()
+{
+return inet_aton ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_network_inet_aton=yes
+else
+  ac_cv_lib_network_inet_aton=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_aton" >&5
+$as_echo "$ac_cv_lib_network_inet_aton" >&6; }
+if test "x$ac_cv_lib_network_inet_aton" = xyes; then :
+
+$as_echo "#define HAVE_INET_ATON 1" >>confdefs.h
+
+            use_libnetwork=yes
+else
   inet_aton=no
+
+fi
+
+
+
 fi
 
 ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton"
@@ -21122,7 +21180,55 @@ $as_echo "#define HAVE_INET_PTON 1" >>confdefs.h
 
     inet_pton=yes
 else
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_pton in -lnetwork" >&5
+$as_echo_n "checking for inet_pton in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_inet_pton+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inet_pton ();
+int
+main ()
+{
+return inet_pton ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_network_inet_pton=yes
+else
+  ac_cv_lib_network_inet_pton=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_pton" >&5
+$as_echo "$ac_cv_lib_network_inet_pton" >&6; }
+if test "x$ac_cv_lib_network_inet_pton" = xyes; then :
+
+$as_echo "#define HAVE_INET_PTON 1" >>confdefs.h
+
+            use_libnetwork=yes
+else
   inet_pton=no
+
+fi
+
+
+
 fi
 
 ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop"
@@ -21132,7 +21238,55 @@ $as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h
 
     inet_ntop=yes
 else
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop in -lnetwork" >&5
+$as_echo_n "checking for inet_ntop in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_inet_ntop+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inet_ntop ();
+int
+main ()
+{
+return inet_ntop ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_network_inet_ntop=yes
+else
+  ac_cv_lib_network_inet_ntop=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntop" >&5
+$as_echo "$ac_cv_lib_network_inet_ntop" >&6; }
+if test "x$ac_cv_lib_network_inet_ntop" = xyes; then :
+
+$as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h
+
+            use_libnetwork=yes
+else
   inet_ntop=no
+
+fi
+
+
+
 fi
 
 
@@ -21140,6 +21294,10 @@ if test "$inet_ntop" = "no" -a "$inet_pton" = "no" ; then
     as_fn_error $? "We need either inet_ntop or inet_pton" "$LINENO" 5
 fi
 
+if test "$use_libnetwork" = "yes" ; then
+	LIBS="-lnetwork $LIBS"
+fi
+
 ac_fn_c_check_func "$LINENO" "inet_addr" "ac_cv_func_inet_addr"
 if test "x$ac_cv_func_inet_addr" = xyes; then :
 
@@ -21151,10 +21309,62 @@ else
 fi
 
 
-if test x$inet_addr = no ; then
+if test x$inet_addr = xno ; then
     as_fn_error $? "We need inet_addr.  See bug 26" "$LINENO" 5
 fi
 
+ac_fn_c_check_func "$LINENO" "fts_read" "ac_cv_func_fts_read"
+if test "x$ac_cv_func_fts_read" = xyes; then :
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fts_read in -lbsd" >&5
+$as_echo_n "checking for fts_read in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_fts_read+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char fts_read ();
+int
+main ()
+{
+return fts_read ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_bsd_fts_read=yes
+else
+  ac_cv_lib_bsd_fts_read=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_fts_read" >&5
+$as_echo "$ac_cv_lib_bsd_fts_read" >&6; }
+if test "x$ac_cv_lib_bsd_fts_read" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBSD 1
+_ACEOF
+
+  LIBS="-lbsd $LIBS"
+
+fi
+
+fi
+
+
 have_tuntap=no
 # Check whether --enable-tuntap was given.
 if test "${enable_tuntap+set}" = set; then :
@@ -21206,7 +21416,7 @@ if test "${with_libpcap+set}" = set; then :
         LPCAPINCDIR=${testdir}
         if test $dynamic_link = yes; then
             for ext in .dylib .so .tbd ; do
-                for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
+                for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                     sharefile=$(ls ${testdir}/$dir/libpcap${ext}* 2> /dev/null | sort | head -n1)
                     if test -n "${sharefile}"; then
                         LPCAP_LD_LIBRARY_PATH="$(dirname ${sharefile})"
@@ -21222,7 +21432,7 @@ if test "${with_libpcap+set}" = set; then :
             done
         else
                                                 for ext in ${libext} .a .A.tbd ; do
-                for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
+                for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                     staticfile=$(ls ${testdir}/$dir/libpcap${ext} 2> /dev/null | sort | head -n1)
                     if test -n "${staticfile}"; then
                         LPCAPLIB="${staticfile}"
@@ -21403,7 +21613,7 @@ $as_echo "$as_me: WARNING: Unable to find libpcap using pcap-config" >&2;}
                 LPCAPINCDIR="${testdir}/include"
                 if test $dynamic_link = yes; then
                     for ext in .dylib .so .tbd; do
-                        for dir in . lib lib64 ${host_cpu} lib/${host_cpu} ${host_cpu}-${host_os} lib/${host_cpu}-${host_os} ${MULTIARCH} lib/${MULTIARCH}; do
+                        for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                             sharefile=$(ls "${testdir}/$dir/libpcap${ext}" 2> /dev/null | sort | head -n1)
                             if test -n "${sharefile}"; then
                                 LPCAPLIB="-L$(dirname ${sharefile}) -lpcap"
@@ -21419,7 +21629,7 @@ $as_echo "$as_me: WARNING: Unable to find libpcap using pcap-config" >&2;}
                 fi
                 if test $foundpcap = no ; then
                                                                                 for ext in ${libext} .a .A.tbd ; do
-                        for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
+                        for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                             staticfile=$(ls "${testdir}/$dir/libpcap${ext}" 2> /dev/null | sort | head -n1)
                             if test -n "${staticfile}"; then
                                 LPCAPLIB="${staticfile}"
@@ -21534,6 +21744,104 @@ $as_echo "$as_me: Unable to find nl library - may be needed by libpcap" >&6;}
 fi
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bpf_object__open_file in -lbpf" >&5
+$as_echo_n "checking for bpf_object__open_file in -lbpf... " >&6; }
+if ${ac_cv_lib_bpf_bpf_object__open_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbpf  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char bpf_object__open_file ();
+int
+main ()
+{
+return bpf_object__open_file ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_bpf_bpf_object__open_file=yes
+else
+  ac_cv_lib_bpf_bpf_object__open_file=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bpf_bpf_object__open_file" >&5
+$as_echo "$ac_cv_lib_bpf_bpf_object__open_file" >&6; }
+if test "x$ac_cv_lib_bpf_bpf_object__open_file" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBPF 1
+_ACEOF
+
+  LIBS="-lbpf $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to find libbpf library " >&5
+$as_echo "$as_me: Unable to find libbpf library " >&6;}
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xsk_umem__delete in -lxdp" >&5
+$as_echo_n "checking for xsk_umem__delete in -lxdp... " >&6; }
+if ${ac_cv_lib_xdp_xsk_umem__delete+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxdp  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char xsk_umem__delete ();
+int
+main ()
+{
+return xsk_umem__delete ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_xdp_xsk_umem__delete=yes
+else
+  ac_cv_lib_xdp_xsk_umem__delete=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xdp_xsk_umem__delete" >&5
+$as_echo "$ac_cv_lib_xdp_xsk_umem__delete" >&6; }
+if test "x$ac_cv_lib_xdp_xsk_umem__delete" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBXDP 1
+_ACEOF
+
+  LIBS="-lxdp $LIBS"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: Unable to find libxdp library " >&5
+$as_echo "$as_me: Unable to find libxdp library " >&6;}
+fi
+
+
 ##
 ## If not automatically configured,
 ## check for newer and full-featured libpcap's
@@ -21961,7 +22269,7 @@ cat >conftest.c <<EOF
 EOF
 ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LPCAPLIB \
     conftest.c $LIBS >/dev/null 2>&1
-if test -x conftest ; then
+if test -x conftest -a "$cross_compiling" != "yes"; then
     full_libpcap_version=$(LD_LIBRARY_PATH="$LPCAP_LD_LIBRARY_PATH" ./conftest)
     libpcap_version=$(echo "$full_libpcap_version" | ${CUT} -d' ' -f3)
     pcap_version_ok=yes
@@ -22402,6 +22710,64 @@ $as_echo "#define HAVE_PCAP_SNAPSHOT 1" >>confdefs.h
 
 fi
 
+have_pcap_open_offline_with_tstamp_precision=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_open_offline_with_tstamp_precision support" >&5
+$as_echo_n "checking for pcap_open_offline_with_tstamp_precision support... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "$LPCAPINC"
+
+int
+main ()
+{
+
+    pcap_t *pcap;
+    char ebuf[PCAP_ERRBUF_SIZE];
+    pcap = pcap_open_offline_with_tstamp_precision("fake.pcap", PCAP_TSTAMP_PRECISION_NANO, &ebuf[0]);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+    have_pcap_open_offline_with_tstamp_precision=yes
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+    have_pcap_open_offline_with_tstamp_precision=no
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+if test $have_pcap_open_offline_with_tstamp_precision = yes ; then
+
+$as_echo "#define HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION 1" >>confdefs.h
+
+
+$as_echo "#define PCAP_TSTAMP_US_TO_NS_MULTIPLIER 1" >>confdefs.h
+
+
+$as_echo "#define PCAP_TSTAMP_US_TO_US_DIVISOR 1000" >>confdefs.h
+
+else
+
+$as_echo "#define PCAP_TSTAMP_US_TO_NS_MULTIPLIER 1000" >>confdefs.h
+
+
+$as_echo "#define PCAP_TSTAMP_US_TO_US_DIVISOR 1" >>confdefs.h
+
+fi
+
 
 # Tcpbridge requires libpcap and pcap_sendpacket()
 enable_tcpbridge=no
@@ -22712,6 +23078,55 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+have_libxdp=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBXDP XDP packet sending support" >&5
+$as_echo_n "checking for LIBXDP XDP packet sending support... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <stdlib.h>
+#include <xdp/xsk.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+
+    struct xsk_socket {
+        struct xsk_ring_cons *rx;
+        struct xsk_ring_prod *tx;
+        struct xsk_ctx *ctx;
+        struct xsk_socket_config config;
+        int fd;
+    };
+    struct xsk_socket xsk;
+	struct xsk_ring_cons *rxr = NULL;
+	struct xsk_ring_prod *txr = NULL;
+    int queue_id = 0;
+    xsk_socket__create(&xsk, "lo", queue_id, NULL, rxr, txr, NULL);
+    socket(AF_XDP, SOCK_RAW, 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+
+$as_echo "#define HAVE_LIBXDP 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    have_libxdp=yes
+
+else
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
 have_tx_ring=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TX_RING socket sending support" >&5
 $as_echo_n "checking for TX_RING socket sending support... " >&6; }
@@ -22752,6 +23167,42 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+for ac_header in bpf/libbpf.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "bpf/libbpf.h" "ac_cv_header_bpf_libbpf_h" "$ac_includes_default"
+if test "x$ac_cv_header_bpf_libbpf_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_BPF_LIBBPF_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in bpf/bpf.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "bpf/bpf.h" "ac_cv_header_bpf_bpf_h" "$ac_includes_default"
+if test "x$ac_cv_header_bpf_bpf_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_BPF_BPF_H 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in xdp/libxdp.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "xdp/libxdp.h" "ac_cv_header_xdp_libxdp_h" "$ac_includes_default"
+if test "x$ac_cv_header_xdp_libxdp_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_XDP_LIBXDP_H 1
+_ACEOF
+
+fi
+
+done
+
 
 for ac_header in net/bpf.h
 do :
@@ -22909,6 +23360,35 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DLT_LINUX_SLL2 in libpcap" >&5
+$as_echo_n "checking for DLT_LINUX_SLL2 in libpcap... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include "$LPCAPINC"
+int
+main ()
+{
+ int foo;
+                 foo = DLT_LINUX_SLL2
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_DLT_LINUX_SLL2 1" >>confdefs.h
+
+                 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DLT_C_HDLC in libpcap" >&5
 $as_echo_n "checking for DLT_C_HDLC in libpcap... " >&6; }
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -23218,7 +23698,7 @@ case "$host_os" in
 EOF
         ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
             conftest.c $LIBS >/dev/null 2>&1
-        if test ! -x conftest ; then
+        if test ! -x conftest -o "$cross_compiling" = "yes" ; then
                         unaligned_cv_fail=yes
         else
             ./conftest >conftest.out
@@ -25781,7 +26261,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by tcpreplay $as_me 4.4.4, which was
+This file was extended by tcpreplay $as_me 4.5.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25848,7 +26328,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-tcpreplay config.status 4.4.4
+tcpreplay config.status 4.5.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -27839,6 +28319,7 @@ pcap_sendpacket:            ${have_pcap_sendpacket} **
 pcap_netmap                 ${have_pcap_netmap}
 Linux/BSD netmap:           ${have_netmap}
 Tuntap device support:      ${have_tuntap}
+LIBXDP for AF_XDP socket:   ${have_libxdp}
 
 * In order of preference; see configure --help to override
 ** Required for tcpbridge
@@ -27868,6 +28349,7 @@ pcap_sendpacket:            ${have_pcap_sendpacket} **
 pcap_netmap                 ${have_pcap_netmap}
 Linux/BSD netmap:           ${have_netmap}
 Tuntap device support:      ${have_tuntap}
+LIBXDP for AF_XDP socket:   ${have_libxdp}
 
 * In order of preference; see configure --help to override
 ** Required for tcpbridge

+ 122 - 11
configure.ac

@@ -4,7 +4,7 @@ dnl $Id$
 AC_PREREQ([2.69])
 
 dnl Set version info here!
-AC_INIT([tcpreplay],[4.4.4],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
+AC_INIT([tcpreplay],[4.5.1],[https://github.com/appneta/tcpreplay/issues],[tcpreplay],[http://tcpreplay.sourceforge.net/])
 AC_CONFIG_SRCDIR([src/tcpreplay.c])
 AC_CONFIG_HEADERS([src/config.h])
 AC_CONFIG_AUX_DIR(config)
@@ -566,6 +566,10 @@ AC_ARG_ENABLE(force-libdnet,
     AS_HELP_STRING([--enable-force-libdnet],[Force using libdnet for sending packets]),
     [ AC_DEFINE([FORCE_INJECT_LIBDNET], [1], [Force using libdnet for sending packets])])
 
+AC_ARG_ENABLE(force-libxdp,
+    AS_HELP_STRING([--enable-force-libxdp],[Force using libxdp for sending packets]),
+    [ AC_DEFINE([FORCE_INJECT_LIBXDP], [1], [Force using libxdp for sending packets])])
+
 AC_ARG_ENABLE(force-inject,
     AS_HELP_STRING([--enable-force-inject],[Force using libpcap's pcap_inject() for sending packets]),
     [ AC_DEFINE([FORCE_INJECT_PCAP_INJECT],[1], [Force using libpcap's pcap_inject() for sending packets])])
@@ -605,32 +609,61 @@ else
 fi
 
 dnl Check for inet_aton and inet_pton
+dnl On Haiku these functions are in libnetwork.
 AC_CHECK_FUNC(inet_aton,
     AC_DEFINE([HAVE_INET_ATON], [1], [Do we have inet_aton?])
     inet_aton=yes,
-    inet_aton=no)
+    [
+        AC_CHECK_LIB(network, inet_aton,
+            AC_DEFINE([HAVE_INET_ATON], [1], [Do we have inet_aton?])
+            use_libnetwork=yes,
+            [inet_aton=no]
+        )
+    ]
+)
 AC_CHECK_FUNC(inet_pton,
     AC_DEFINE([HAVE_INET_PTON], [1], [Do we have inet_pton?])
     inet_pton=yes,
-    inet_pton=no)
+    [
+        AC_CHECK_LIB(network, inet_pton,
+            AC_DEFINE([HAVE_INET_PTON], [1], [Do we have inet_pton?])
+            use_libnetwork=yes,
+            [inet_pton=no]
+        )
+    ]
+)
 AC_CHECK_FUNC(inet_ntop,
     AC_DEFINE([HAVE_INET_NTOP], [1], [Do we have inet_ntop?])
     inet_ntop=yes,
-    inet_ntop=no)
+    [
+        AC_CHECK_LIB(network, inet_ntop,
+            AC_DEFINE([HAVE_INET_NTOP], [1], [Do we have inet_ntop?])
+            use_libnetwork=yes,
+            [inet_ntop=no]
+        )
+    ]
+)
 
 if test "$inet_ntop" = "no" -a "$inet_pton" = "no" ; then
     AC_MSG_ERROR([We need either inet_ntop or inet_pton])
 fi
 
+if test "$use_libnetwork" = "yes" ; then
+	LIBS="-lnetwork $LIBS"
+fi
+
 AC_CHECK_FUNC(inet_addr,
     AC_DEFINE([HAVE_INET_ADDR], [1], [Do we have inet_addr?])
     inet_addr=yes,
     inet_addr=no)
 
-if test x$inet_addr = no ; then
+if test x$inet_addr = xno ; then
     AC_MSG_ERROR([We need inet_addr.  See bug 26])
 fi
 
+dnl On Haiku fts_*() functions are in libbsd.
+AC_CHECK_FUNC(fts_read,,[AC_CHECK_LIB(bsd, fts_read)])
+
 dnl #####################################################
 dnl Checks for tuntap device support
 dnl #####################################################
@@ -671,7 +704,7 @@ AC_ARG_WITH(libpcap,
         LPCAPINCDIR=${testdir}
         if test $dynamic_link = yes; then
             for ext in .dylib .so .tbd ; do
-                for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
+                for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                     sharefile=$(ls ${testdir}/$dir/libpcap${ext}* 2> /dev/null | sort | head -n1)
                     if test -n "${sharefile}"; then
                         LPCAP_LD_LIBRARY_PATH="$(dirname ${sharefile})"
@@ -690,7 +723,7 @@ AC_ARG_WITH(libpcap,
             dnl If dynamic library not found, try static
             dnl
             for ext in ${libext} .a .A.tbd ; do
-                for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
+                for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                     staticfile=$(ls ${testdir}/$dir/libpcap${ext} 2> /dev/null | sort | head -n1)
                     if test -n "${staticfile}"; then
                         LPCAPLIB="${staticfile}"
@@ -771,7 +804,7 @@ AC_ARG_WITH(libpcap,
                 LPCAPINCDIR="${testdir}/include"
                 if test $dynamic_link = yes; then
                     for ext in .dylib .so .tbd; do
-                        for dir in . lib lib64 ${host_cpu} lib/${host_cpu} ${host_cpu}-${host_os} lib/${host_cpu}-${host_os} ${MULTIARCH} lib/${MULTIARCH}; do
+                        for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                             sharefile=$(ls "${testdir}/$dir/libpcap${ext}" 2> /dev/null | sort | head -n1)
                             if test -n "${sharefile}"; then
                                 LPCAPLIB="-L$(dirname ${sharefile}) -lpcap"
@@ -790,7 +823,7 @@ AC_ARG_WITH(libpcap,
                     dnl If dynamic library not found, try static
                     dnl
                     for ext in ${libext} .a .A.tbd ; do
-                        for dir in . lib lib64 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
+                        for dir in . lib lib64 lib32 lib/${host_cpu}-${host_os} ${host_cpu}-${host_os} lib/${MULTIARCH} ${MULTIARCH}; do
                             staticfile=$(ls "${testdir}/$dir/libpcap${ext}" 2> /dev/null | sort | head -n1)
                             if test -n "${staticfile}"; then
                                 LPCAPLIB="${staticfile}"
@@ -844,6 +877,12 @@ fi
 AC_SEARCH_LIBS([nl_handle_alloc], [nl],
         [AC_MSG_NOTICE([Unable to find nl library - may be needed by libpcap])])
 
+AC_CHECK_LIB(bpf, bpf_object__open_file,,
+        [AC_MSG_NOTICE([Unable to find libbpf library ])])
+
+AC_CHECK_LIB(xdp, xsk_umem__delete,,
+        [AC_MSG_NOTICE([Unable to find libxdp library ])])
+
 ##
 ## If not automatically configured,
 ## check for newer and full-featured libpcap's
@@ -928,7 +967,7 @@ cat >conftest.c <<EOF
 EOF
 ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LPCAPLIB \
     conftest.c $LIBS >/dev/null 2>&1
-if test -x conftest ; then
+if test -x conftest -a "$cross_compiling" != "yes"; then
     full_libpcap_version=$(LD_LIBRARY_PATH="$LPCAP_LD_LIBRARY_PATH" ./conftest)
     libpcap_version=$(echo "$full_libpcap_version" | ${CUT} -d' ' -f3)
     pcap_version_ok=yes
@@ -1184,6 +1223,35 @@ if test $have_pcap_snapshot = yes ; then
               [Does libpcap have pcap_snapshot?])
 fi
 
+have_pcap_open_offline_with_tstamp_precision=no
+dnl Check to see if we've got pcap_open_offline_with_tstamp_precision()
+AC_MSG_CHECKING(for pcap_open_offline_with_tstamp_precision support)
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "$LPCAPINC"
+]],[[
+    pcap_t *pcap;
+    char ebuf[PCAP_ERRBUF_SIZE];
+    pcap = pcap_open_offline_with_tstamp_precision("fake.pcap", PCAP_TSTAMP_PRECISION_NANO, &ebuf[0]);
+]])],[
+    have_pcap_open_offline_with_tstamp_precision=yes
+    AC_MSG_RESULT(yes)
+], [
+    have_pcap_open_offline_with_tstamp_precision=no
+    AC_MSG_RESULT(no)
+])
+
+if test $have_pcap_open_offline_with_tstamp_precision = yes ; then
+    AC_DEFINE([HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION], [1], [Does libpcap have pcap_open_offline_with_tstamp_precision?])
+    AC_DEFINE([PCAP_TSTAMP_US_TO_NS_MULTIPLIER], [1], [Multiplier for conversion from PCAP usec to nsec])
+    AC_DEFINE([PCAP_TSTAMP_US_TO_US_DIVISOR], [1000], [Divisor for conversion from PCAP usec to usec])
+else
+   AC_DEFINE([PCAP_TSTAMP_US_TO_NS_MULTIPLIER], [1000], [Multiplier for conversion from PCAP usec to nsec])
+   AC_DEFINE([PCAP_TSTAMP_US_TO_US_DIVISOR], [1], [Divisor for conversion from PCAP usec to usec])
+fi
+
 
 # Tcpbridge requires libpcap and pcap_sendpacket()
 enable_tcpbridge=no
@@ -1399,6 +1467,36 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
     AC_MSG_RESULT(no)
 ])
 
+have_libxdp=no
+dnl Check for LIBXDP AF_XDP socket support
+AC_MSG_CHECKING(for LIBXDP XDP packet sending support)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stdlib.h>
+#include <xdp/xsk.h>
+#include <sys/socket.h>
+]], [[
+    struct xsk_socket {
+        struct xsk_ring_cons *rx;
+        struct xsk_ring_prod *tx;
+        struct xsk_ctx *ctx;
+        struct xsk_socket_config config;
+        int fd;
+    };
+    struct xsk_socket xsk;
+	struct xsk_ring_cons *rxr = NULL;
+	struct xsk_ring_prod *txr = NULL;
+    int queue_id = 0;
+    xsk_socket__create(&xsk, "lo", queue_id, NULL, rxr, txr, NULL);
+    socket(AF_XDP, SOCK_RAW, 0);
+]])],[
+    AC_DEFINE([HAVE_LIBXDP], [1],
+            [Do we have LIBXDP AF_XDP socket support?])
+    AC_MSG_RESULT(yes)
+    have_libxdp=yes
+],[
+    AC_MSG_RESULT(no)
+])
+
 have_tx_ring=no
 dnl Check for older Linux TX_RING support
 AC_MSG_CHECKING(for TX_RING socket sending support)
@@ -1420,6 +1518,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
     AC_MSG_RESULT(no)
 ])
 
+AC_CHECK_HEADERS([bpf/libbpf.h])
+AC_CHECK_HEADERS([bpf/bpf.h])
+AC_CHECK_HEADERS([xdp/libxdp.h])
 
 AC_CHECK_HEADERS([net/bpf.h], [have_bpf=yes], [have_bpf=no])
 if test $have_bpf = yes ; then
@@ -1525,6 +1626,15 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo;
                ],[AC_MSG_RESULT(no)
                ])
 
+AC_MSG_CHECKING(for DLT_LINUX_SLL2 in libpcap)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo;
+                 foo = DLT_LINUX_SLL2
+               ]])],[ AC_DEFINE([HAVE_DLT_LINUX_SLL2], [1],
+                           [Does pcap.h include a header with DLT_LINUX_SLL2?])
+                 AC_MSG_RESULT(yes)
+               ],[AC_MSG_RESULT(no)
+               ])
+
 AC_MSG_CHECKING(for DLT_C_HDLC in libpcap)
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include "$LPCAPINC"]], [[ int foo;
                  foo = DLT_C_HDLC ]])],[ AC_DEFINE([HAVE_DLT_C_HDLC], [1],
@@ -1709,7 +1819,7 @@ case "$host_os" in
 EOF
         ${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS \
             conftest.c $LIBS >/dev/null 2>&1
-        if test ! -x conftest ; then
+        if test ! -x conftest -o "$cross_compiling" = "yes" ; then
             dnl failed to compile for some reason
             unaligned_cv_fail=yes
         else
@@ -1939,6 +2049,7 @@ pcap_sendpacket:            ${have_pcap_sendpacket} **
 pcap_netmap                 ${have_pcap_netmap}
 Linux/BSD netmap:           ${have_netmap}
 Tuntap device support:      ${have_tuntap}
+LIBXDP for AF_XDP socket:   ${have_libxdp}
 
 * In order of preference; see configure --help to override
 ** Required for tcpbridge

+ 41 - 6
docs/CHANGELOG

@@ -1,7 +1,41 @@
+07/12/2024 Version 4.5.1
+    - NULL Pointer Dereference in parse_endpoints (#888)
+    - tcpreplay --include / --exclude to control which packets are replayed (#884)
+    - add -W (--suppress-warnings) option to suppress warning messages (#878)
+    - AF_XDP compile issue due to merge issue (#876)
+    - memory leak in tcpprep when using include/exclude (#869)
+    - memory leak in tcpprep when using RegEx (#867)
+    - fix nanosecond timestamp regression bug (#863)
+    - autotools - AC_HELP_STRING is obsolete in 2.70 (#856)
+    - add -w output.pcap command line option to direct the output to a pcap (#853)
+    - configure.ac: do not run conftest in case of cross compilation (#849)
+    - Haiku support (#847)
+    - --fixhdrlen option added to control action on packet length changes (#846)
+    - incorrect checksum for certain IPv4 packets - fixed by #846 (#844)
+    - add check for IPv6 extension header length (#827 #842)
+    - GitHub template for pull requests (#839)
+    - improved 802.3 (Ethernet I) handling and warning messages (#835)
+    - handle IPv6 fragment extension header (#832 #837)
+    - Linux tap interfaces fail intermittently (#828)
+    - Infinite loop in tcprewrite at get.c (#827 #842)
+    - SLL incorrect size and protocol when converted to Ethernet (#826)
+    - CVE-2023-43279 add check for empty CIDR (#824 #843)
+    - AF_XDP socket extension (#822 #823)
+    - configure.ac: unify search dirs for pcap and add lib32 (#819)
+    - tcpreplay-edit recomputes IPv4 checksums unnecessarily (#815 #846)
+    - CVE-2023-4256 double free in tcprewrite DLT_JUNIPER_ETHER (#813 #851)
+    - dlt_jnpr_ether_cleanup: check config before cleanup (#812 #851)
+    - SEGV on invalid Juniper Ethernet header length (#811)
+    - nanosecond timestamps support (#796)
+    - Linux cooked packet fatal error (#792)
+    - low PPS values run at full speed after several days (#779)
+    - create DLT_LINUX_SLL2 plugin (#727)
+
 06/04/2023 Version 4.4.4
     - overflow check fix for parse_mpls (#795)
     - tcpreplay-edit: prevent L2 flooding of ipv6 unicast packets (#793)
-    - CVE-2023-27786 bugs caused by strtok_r (#782 #784 #785 #786 #787 #788)
+    - CVE-2023-27784 CVE-2023-27785 CVE-2023-27786 CVE-2023-27787 CVE-2023-27788 CVE-2023-27789
+      bugs caused by strtok_r (#782 #784 #785 #786 #787 #788)
     - CVE-2023-27783 reachable assert in tcpedit_dlt_cleanup (#780)
     - add CI and C/C++ Linter and CodeQL (#773)
     - reachable assert in fast_edit_packet (#772)
@@ -33,15 +67,16 @@
     - build failures Debian/kfreebsd (#706)
     - bus error when building on armhf (#705)
     - typo fixes (#704)
-    - heap buffer overflow in tcpreplay (#703)
-    - double free in Juniper DLT (#702)
+    - CVE-2022-27418 heap buffer overflow in tcpreplay (#703)
+    - CVE-2022-27416 double free in Juniper DLT (#702)
 
 01/31/2022 Version 4.4.0
     - remove obsolete FORCE_ALIGN support to fix macOS 11 compile (#695)
     - add a security policy document (#689)
+    - CVE-2021-45386 CVE-2021-45387 two reachable assertions in add_tree_ipv4() and add_tree_ipv6() (#687 #678)
     - ability to specify directory of pcap files (#682)
     - incorrect PPS rate for long-running sessions (#679)
-    - option --skipbroadcast not working (#677)
+    - option --skipbroadcast not working (#677 #678)
     - revert #630 to fix --multiplier issues (#674)
     - gcc 9.3 compiler warnings (#670)
     - installed netmap not automatically detected (#669)
@@ -80,7 +115,7 @@
     - CVE-2018-20553 Correct L2 header length calculations so that IP header offset is correct (#584)
     - Correct L2 header length to correct IP header offset (#583)
     - Fix warnings from gcc version 10 (#580)
-    - Heap Buffer Overflow in randomize_iparp (#579)
+    -  CVE-2020-23273 Heap Buffer Overflow in randomize_iparp (#579)
     - Use after free in get_ipv6_next (#578)
     - CVE-2020-12740 Heap Buffer Overflow in git_ipv6_next (#576)
     - Call pcap_freecode() on pcap_compile() (#572)
@@ -88,7 +123,7 @@
     - Fix divide by zero in fuzzing (#570)
     - Unique IP repeats at very high iteration counts (#566)
     - Fails to compile on FreeBSD amd64 13.0 (#558)
-    - Heap Buffer Overflow in do_checksum (#556) (#577)
+    - CVE-2020-18976 Heap Buffer Overflow in do_checksum (#556) (#577)
     - Attempt to correct corrupt pcap files, if possible (#557)
     - Fix GCC v10 warnings (#555)
     - Remove some duplicated SOURCES entries (#551)

+ 27 - 0
docs/CREDIT

@@ -113,3 +113,30 @@ Florian Weimer <GitHub @fweimer-rh>
 
 David Guti <GitHub @david-guti>
     - prevent L2 flooding of ipv6 unicast packets for tcpreplay-edit
+
+Bastian Triller <GitHub @btriller>
+    - Linux SLL2
+
+GithHub @plangarbalint
+    - eBPF (AF_XDF)
+    - nanosecond timers
+
+Chuck Cottrill <GitHub @ChuckCottrill>
+    - handle IPv6 fragment extensions
+    - --fixhdrlen option
+    - bug fixes
+
+Martin 'JaMa' Jansa <GitHub @shr-project>
+    - configure.ac: unify search dirs for pcap and add lib32
+
+Marsman <GitHub Marsman1996>
+    - dlt_jnpr_ether_cleanup: check config before cleanup
+
+Chen Qi <GitHub ChenQi1989>
+    - configure.ac: do not run conftest in case of cross compilation
+
+Denis Ovsienko <GitHub infrastation>
+    - Haiku support
+
+Jason Lue <GitHub jasonlue>
+    - tcpreplay -w option

+ 29 - 0
docs/INSTALL

@@ -128,6 +128,35 @@ directory, for example:
     make
     sudo make install
 
+2) AF_XDF
+   ------
+
+This feature will detect AF_XDP capable network drivers on Linux. If detected,
+the `--xdp` option becomes available, allowing eBPF enabled adapters to be
+written to directly.
+
+This feature requires `libxdp-dev` and `libbpf-dev` packages to be installed.
+For example:
+
+    $ sudo apt install -y libxdp-dev libbpf-dev
+    $ ./configure | tail
+    Linux/BSD netmap:           no
+    Tuntap device support:      yes
+    LIBXDP for AF_XDP socket:   yes
+    $ make
+    $ sudo make install
+    $ tcpreplay -i eth0 --xdp test/test.pcap
+
+If you want to compile a version that only uses AF_XDP, use the `--enable-force-libxdp`
+configure option, e.g.
+
+    $ ./configure --enable-force-libxdp | tail
+    Linux/BSD netmap:           no
+    Tuntap device support:      yes
+    LIBXDP for AF_XDP socket:   yes
+    $ make
+    $ sudo make install
+    $ tcpreplay -i eth0 test/test.pcap
 
 Compilers and Options
 =====================

+ 67 - 44
lib/sll.h

@@ -1,10 +1,10 @@
 /*-
  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
- *	The Regents of the University of California.  All rights reserved.
+ *    The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from the Stanford/CMU enet packet filter,
  * (net/enet.c) distributed as part of 4.3BSD, and code contributed
- * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
  * Berkeley Laboratory.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,30 +42,30 @@
  * For captures on Linux cooked sockets, we construct a fake header
  * that includes:
  *
- *	a 2-byte "packet type" which is one of:
+ *    a 2-byte "packet type" which is one of:
  *
- *		LINUX_SLL_HOST		packet was sent to us
- *		LINUX_SLL_BROADCAST	packet was broadcast
- *		LINUX_SLL_MULTICAST	packet was multicast
- *		LINUX_SLL_OTHERHOST	packet was sent to somebody else
- *		LINUX_SLL_OUTGOING	packet was sent *by* us;
+ *        LINUX_SLL_HOST         packet was sent to us
+ *        LINUX_SLL_BROADCAST    packet was broadcast
+ *        LINUX_SLL_MULTICAST    packet was multicast
+ *        LINUX_SLL_OTHERHOST    packet was sent to somebody else
+ *        LINUX_SLL_OUTGOING     packet was sent *by* us;
  *
- *	a 2-byte Ethernet protocol field;
+ *    a 2-byte Ethernet protocol field;
  *
- *	a 2-byte link-layer type;
+ *    a 2-byte link-layer type;
  *
- *	a 2-byte link-layer address length;
+ *    a 2-byte link-layer address length;
  *
- *	an 8-byte source link-layer address, whose actual length is
- *	specified by the previous value.
+ *    an 8-byte source link-layer address, whose actual length is
+ *    specified by the previous value.
  *
  * All fields except for the link-layer address are in network byte order.
  *
  * DO NOT change the layout of this structure, or change any of the
  * LINUX_SLL_ values below.  If you must change the link-layer header
  * for a "cooked" Linux capture, introduce a new DLT_ type (ask
- * "tcpdump-workers@tcpdump.org" for one, so that you don't give it a
- * value that collides with a value already being used), and use the
+ * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it
+ * a value that collides with a value already being used), and use the
  * new header in captures of that type, so that programs that can
  * handle DLT_LINUX_SLL captures will continue to handle them correctly
  * without any change, and so that capture files with different headers
@@ -77,54 +77,77 @@
 #ifndef _SLL_H_
 #define _SLL_H_
 
+//#include <pcap/pcap-inttypes.h>
+#include <inttypes.h>
+
 /*
  * A DLT_LINUX_SLL fake link-layer header.
  */
-#define SLL_HDR_LEN	16          /* total header length */
-#define SLL_ADDRLEN	8           /* length of address field */
+#define SLL_HDR_LEN    16           /* total header length */
+#define SLL_ADDRLEN    8            /* length of address field */
 
 struct sll_header {
-    u_int16_t sll_pkttype;      /* packet type */
-    u_int16_t sll_hatype;       /* link-layer address type */
-    u_int16_t sll_halen;        /* link-layer address length */
+    u_int16_t sll_pkttype;          /* packet type */
+    u_int16_t sll_hatype;           /* link-layer address type */
+    u_int16_t sll_halen;            /* link-layer address length */
     u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */
-    u_int16_t sll_protocol;     /* protocol */
+    u_int16_t sll_protocol;         /* protocol */
+};
+
+/*
+ * A DLT_LINUX_SLL2 fake link-layer header.
+ */
+#define SLL2_HDR_LEN    20              /* total header length */
+
+struct sll2_header {
+    u_int16_t sll2_protocol;            /* protocol */
+    u_int16_t sll2_reserved_mbz;        /* reserved - must be zero */
+    u_int32_t sll2_if_index;            /* 1-based interface index */
+    u_int16_t sll2_hatype;              /* link-layer address type */
+    u_int8_t  sll2_pkttype;             /* packet type */
+    u_int8_t  sll2_halen;               /* link-layer address length */
+    u_int8_t  sll2_addr[SLL_ADDRLEN];   /* link-layer address */
 };
 
 /*
- * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the
- * PACKET_ values on Linux, but are defined here so that they're
- * available even on systems other than Linux, and so that they
- * don't change even if the PACKET_ values change.
+ * The LINUX_SLL_ values for "sll_pkttype" and LINUX_SLL2_ values for
+ * "sll2_pkttype"; these correspond to the PACKET_ values on Linux,
+ * which are defined by a header under include/uapi in the current
+ * kernel source, and are thus not going to change on Linux.  We
+ * define them here so that they're available even on systems other
+ * than Linux.
  */
-#define LINUX_SLL_HOST		0
-#define LINUX_SLL_BROADCAST	1
-#define LINUX_SLL_MULTICAST	2
-#define LINUX_SLL_OTHERHOST	3
-#define LINUX_SLL_OUTGOING	4
+#define LINUX_SLL_HOST         0
+#define LINUX_SLL_BROADCAST    1
+#define LINUX_SLL_MULTICAST    2
+#define LINUX_SLL_OTHERHOST    3
+#define LINUX_SLL_OUTGOING     4
 
 /*
- * The LINUX_SLL_ values for "sll_protocol"; these correspond to the
- * ETH_P_ values on Linux, but are defined here so that they're
- * available even on systems other than Linux.  We assume, for now,
- * that the ETH_P_ values won't change in Linux; if they do, then:
+ * The LINUX_SLL_ values for "sll_protocol" and LINUX_SLL2_ values for
+ * "sll2_protocol"; these correspond to the ETH_P_ values on Linux, but
+ * are defined here so that they're available even on systems other than
+ * Linux.  We assume, for now, that the ETH_P_ values won't change in
+ * Linux; if they do, then:
  *
- *	if we don't translate them in "pcap-linux.c", capture files
- *	won't necessarily be readable if captured on a system that
- *	defines ETH_P_ values that don't match these values;
+ *    if we don't translate them in "pcap-linux.c", capture files
+ *    won't necessarily be readable if captured on a system that
+ *    defines ETH_P_ values that don't match these values;
  *
- *	if we do translate them in "pcap-linux.c", that makes life
- *	unpleasant for the BPF code generator, as the values you test
- *	for in the kernel aren't the values that you test for when
- *	reading a capture file, so the fixup code run on BPF programs
- *	handed to the kernel ends up having to do more work.
+ *    if we do translate them in "pcap-linux.c", that makes life
+ *    unpleasant for the BPF code generator, as the values you test
+ *    for in the kernel aren't the values that you test for when
+ *    reading a capture file, so the fixup code run on BPF programs
+ *    handed to the kernel ends up having to do more work.
  *
  * Add other values here as necessary, for handling packet types that
  * might show up on non-Ethernet, non-802.x networks.  (Not all the ones
  * in the Linux "if_ether.h" will, I suspect, actually show up in
  * captures.)
  */
-#define LINUX_SLL_P_802_3	0x0001  /* Novell 802.3 frames without 802.2 LLC header */
-#define LINUX_SLL_P_802_2	0x0004  /* 802.2 frames (not D/I/X Ethernet) */
+#define LINUX_SLL_P_802_3    0x0001      /* Novell 802.3 frames without 802.2 LLC header */
+#define LINUX_SLL_P_802_2    0x0004     /* 802.2 frames (not D/I/X Ethernet) */
+#define LINUX_SLL_P_CAN      0x000C     /* CAN frames, with SocketCAN pseudo-headers */
+#define LINUX_SLL_P_CANFD    0x000D     /* CAN FD frames, with SocketCAN pseudo-headers */
 
 #endif

+ 1 - 1
lib/strlcpy.h

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 3 - 3
libopts/m4/libopts.m4

@@ -478,7 +478,7 @@ AC_DEFUN([LIBOPTS_CHECK_COMMON],[
   m4_pushdef([AO_Libopts_Dir],
 	    [ifelse($1, , [libopts], [$1])])
   AC_ARG_ENABLE([local-libopts],
-    AC_HELP_STRING([--enable-local-libopts],
+    AS_HELP_STRING([--enable-local-libopts],
        [Use the supplied libopts tearoff code]),[
     if test x$enableval = xyes ; then
        AC_MSG_NOTICE([Using supplied libopts tearoff])
@@ -488,14 +488,14 @@ AC_DEFUN([LIBOPTS_CHECK_COMMON],[
     fi])
 
   AC_ARG_ENABLE([libopts-install],
-    AC_HELP_STRING([--enable-libopts-install],
+    AS_HELP_STRING([--enable-libopts-install],
        [Install libopts with client installation]))
   AM_CONDITIONAL([INSTALL_LIBOPTS],[test "X${enable_libopts_install}" = Xyes])
 
   [if test -z "${NEED_LIBOPTS_DIR}" ; then]
      AC_MSG_CHECKING([whether autoopts-config can be found])
      AC_ARG_WITH([autoopts-config],
-        AC_HELP_STRING([--with-autoopts-config],
+        AS_HELP_STRING([--with-autoopts-config],
              [specify the config-info script]),
         [lo_cv_with_autoopts_config=${with_autoopts_config}],
         AC_CACHE_CHECK([whether autoopts-config is specified],

+ 3 - 3
src/bridge.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -210,8 +210,8 @@ do_bridge(tcpbridge_opt_t *options, tcpedit_t *tcpedit)
         do_bridge_bidirectional(options, tcpedit);
     }
 
-    if (gettimeofday(&stats.end_time, NULL) < 0)
-        errx(-1, "gettimeofday() failed: %s", strerror(errno));
+    if (get_current_time(&stats.end_time) < 0)
+        errx(-1, "get_current_time() failed: %s", strerror(errno));
     packet_stats(&stats);
 }
 

+ 1 - 1
src/bridge.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common/cache.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common/cache.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 7 - 1
src/common/cidr.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -249,6 +249,10 @@ parse_cidr(tcpr_cidr_t **cidrdata, char *cidrin, char *delim)
     char *network;
     char *token = NULL;
 
+    if (cidrin == NULL) {
+        errx(-1, "%s", "Unable to parse empty CIDR");
+    }
+
     mask_cidr6(&cidrin, delim);
 
     /* first iteration of input using strtok */
@@ -333,6 +337,8 @@ parse_endpoints(tcpr_cidrmap_t **cidrmap1, tcpr_cidrmap_t **cidrmap2, const char
         /* do again with the second IP */
         memset(newmap, '\0', NEWMAP_LEN);
         map = strtok_r(NULL, ":", &token);
+        if (map == NULL)
+            goto done;
 
         strlcpy(newmap, "0.0.0.0/0:", NEWMAP_LEN);
         strlcat(newmap, map, NEWMAP_LEN);

+ 1 - 1
src/common/cidr.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 22 - 0
src/common/dlt_names.c

@@ -506,6 +506,28 @@ char *dlt2name[] = {
         "Unknown",
         "Unknown",
         "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "Unknown",
+        "DLT_LINUX_SLL2",
         NULL
 };
 

+ 4 - 0
src/common/dlt_names.h

@@ -186,6 +186,10 @@ extern const char *dlt2name[];
 #define DLT_LINUX_SLL 113
 #endif
 
+#ifndef DLT_LINUX_SLL2
+#define DLT_LINUX_SLL2 276
+#endif
+
 #ifndef DLT_LTALK
 #define DLT_LTALK 114
 #endif

+ 3 - 1
src/common/err.c

@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2001-2010 Aaron Turner.
  *
- * Copyright (c) 2013-2022 Fred Klassen - AppNeta
+ * Copyright (c) 2013-2024 Fred Klassen - AppNeta
  *
  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
  *
@@ -50,6 +50,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+int print_warnings = 1;
+
 /**
  * writes a notice message to stderr.  Always forces a newline
  */

+ 9 - 5
src/common/err.h

@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2001-2010 Aaron Turner.
  *
- * Copyright (c) 2013-2022 Fred Klassen - AppNeta
+ * Copyright (c) 2013-2024 Fred Klassen - AppNeta
  *
  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
  *
@@ -50,6 +50,8 @@
 #include "defines.h"
 #include <stdlib.h>
 
+extern int print_warnings;
+
 #ifdef DEBUG
 extern int debug;
 #endif
@@ -84,12 +86,14 @@ void notice(const char *fmt, ...);
         fprintf(stderr, "DEBUG%d in %s:%s() line %d: " y "\n", x, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \
     } \
 } while(0)
-        
-
-#define warn(x) fprintf(stderr, "Warning in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, x)
 
+#define warn(x)                                                                                                        \
+        if (print_warnings)                                                                                            \
+            fprintf(stderr, "Warning in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, x)
 
-#define warnx(x, ...) fprintf(stderr, "Warning in %s:%s() line %d:\n" x "\n", __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
+#define warnx(x, ...)                                                                                                  \
+    if (print_warnings)                                                                                                \
+    fprintf(stderr, "Warning in %s:%s() line %d:\n" x "\n", __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
 
 #define err(x, y) do { \
         fprintf(stderr, "\nFatal Error in %s:%s() line %d:\n%s\n", __FILE__, __FUNCTION__, __LINE__, y); \

+ 1 - 1
src/common/fakepcap.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 5 - 1
src/common/fakepcap.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 
@@ -29,6 +29,10 @@
 #define DLT_LINUX_SLL 113
 #endif
 
+#ifndef HAVE_DLT_LINUX_SLL2
+#define DLT_LINUX_SLL2 276
+#endif
+
 #ifndef HAVE_DLT_C_HDLC
 #define DLT_C_HDLC 104
 #endif

+ 3 - 2
src/common/fakepcapnav.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -26,6 +26,7 @@
 #include "defines.h"
 #include "config.h"
 #include "common.h"
+#include "utils.h"
 #include <stdlib.h>
 
 #ifndef HAVE_PCAPNAV
@@ -52,7 +53,7 @@ pcapnav_open_offline(const char *filename)
         err(-1, "malloc() error: unable to malloc pcapnav_t");
     }
 
-    pcapnav->pcap = pcap_open_offline(filename, errbuf);
+    pcapnav->pcap = tcpr_pcap_open(filename, errbuf);
     if (pcapnav->pcap == NULL) {
         errx(-1, "Error opening pcap file %s: %s", filename, errbuf);
     }

+ 1 - 1
src/common/fakepcapnav.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 69 - 22
src/common/flows.c

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 
@@ -157,8 +157,13 @@ static inline flow_entry_type_t hash_put_data(flow_hash_table_t *fht, const uint
 /*
  * Decode the packet, study it's flow status and report
  */
-flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *pkthdr,
-        const u_char *pktdata, const int datalink, const int expiry)
+flow_entry_type_t
+flow_decode(flow_hash_table_t *fht,
+            const struct pcap_pkthdr *pkthdr,
+            const u_char *pktdata,
+            const int datalink,
+            const int expiry,
+            COUNTER packetnum)
 {
     uint32_t pkt_len = pkthdr->caplen;
     const u_char *packet = pktdata;
@@ -195,30 +200,52 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *
                              &vlan_offset);
 
     if (res == -1) {
-        warnx("Unable to process unsupported DLT type: %s (0x%x)",
-              pcap_datalink_val_to_description(datalink), datalink);
+        warnx("flow_decode failed to determine %s header length for packet " COUNTER_SPEC "",
+              pcap_datalink_val_to_description(datalink),
+              packetnum);
         return FLOW_ENTRY_INVALID;
     }
 
     if (ether_type == ETHERTYPE_IP) {
-        if (pkt_len < l2len + sizeof(ipv4_hdr_t))
-                return FLOW_ENTRY_INVALID;
+        size_t required_len = sizeof(ipv4_hdr_t) + l2len;
+        if (pkt_len < required_len) {
+            warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for IPv4 header but only %d available",
+                  packetnum,
+                  required_len,
+                  pkt_len);
+            return FLOW_ENTRY_INVALID;
+        }
 
         ip_hdr = (ipv4_hdr_t *)(packet + l2len);
 
-        if (ip_hdr->ip_v != 4)
+        if (ip_hdr->ip_v != 4) {
+            warnx("flow_decode: packet " COUNTER_SPEC " IPv4 header version should be 4 but instead is %u",
+                  packetnum,
+                  ip_hdr->ip_v);
             return FLOW_ENTRY_NON_IP;
+        }
 
         ip_len = ip_hdr->ip_hl * 4;
         protocol = ip_hdr->ip_p;
         entry.src_ip.in = ip_hdr->ip_src;
         entry.dst_ip.in = ip_hdr->ip_dst;
     } else if (ether_type == ETHERTYPE_IP6) {
-        if (pkt_len < l2len + sizeof(ipv6_hdr_t))
-                return FLOW_ENTRY_INVALID;
+        size_t required_len = sizeof(ipv6_hdr_t) + l2len;
+        if (pkt_len < required_len) {
+            warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for IPv6 header but only %d available",
+                  packetnum,
+                  required_len,
+                  pkt_len);
+            return FLOW_ENTRY_INVALID;
+        }
 
-        if ((packet[0] >> 4) != 6)
+        uint8_t ip6_version = packet[0] >> 4;
+        if (ip6_version != 6) {
+            warnx("flow_decode: packet " COUNTER_SPEC " IPv6 header version should be 6 but instead is %u",
+                  packetnum,
+                  ip6_version);
             return FLOW_ENTRY_NON_IP;
+        }
 
         ip6_hdr = (ipv6_hdr_t *)(packet + l2len);
         ip_len = sizeof(*ip6_hdr);
@@ -238,30 +265,50 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht, const struct pcap_pkthdr *
     entry.protocol = protocol;
 
     switch (protocol) {
-    case IPPROTO_UDP:
-        if (pkt_len < (l2len + ip_len + sizeof(udp_hdr_t)))
+    case IPPROTO_UDP: {
+        size_t required_len = sizeof(udp_hdr_t) + l2len + ip_len;
+        if (pkt_len < required_len) {
+            warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for UDP header but only %d available",
+                  packetnum,
+                  required_len,
+                  pkt_len);
             return FLOW_ENTRY_INVALID;
-        udp_hdr = (udp_hdr_t*)(packet + ip_len + l2len);
+        }
+        udp_hdr = (udp_hdr_t *)(packet + ip_len + l2len);
         entry.src_port = udp_hdr->uh_sport;
         entry.dst_port = udp_hdr->uh_dport;
         break;
-
-    case IPPROTO_TCP:
-        if (pkt_len < (l2len + ip_len + sizeof(tcp_hdr_t)))
+    }
+    case IPPROTO_TCP: {
+        size_t required_len = sizeof(tcp_hdr_t) + l2len + ip_len;
+        if (pkt_len < required_len) {
+            warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for TCP header but only %d available",
+                  packetnum,
+                  required_len,
+                  pkt_len);
             return FLOW_ENTRY_INVALID;
-        tcp_hdr = (tcp_hdr_t*)(packet + ip_len + l2len);
+        }
+        tcp_hdr = (tcp_hdr_t *)(packet + ip_len + l2len);
         entry.src_port = tcp_hdr->th_sport;
         entry.dst_port = tcp_hdr->th_dport;
         break;
-
+    }
     case IPPROTO_ICMP:
-    case IPPROTO_ICMPV6:
-        if (pkt_len < (l2len + ip_len + sizeof(icmpv4_hdr_t)))
+    case IPPROTO_ICMPV6: {
+        size_t required_len = sizeof(icmpv4_hdr_t) + l2len + ip_len;
+        if (pkt_len < required_len) {
+            warnx("flow_decode: packet " COUNTER_SPEC " needs at least %zd bytes for %s header but only %d available",
+                  packetnum,
+                  required_len,
+                  (protocol == IPPROTO_ICMP) ? "ICMP" : "ICMPv6",
+                  pkt_len);
             return FLOW_ENTRY_INVALID;
-        icmp_hdr = (icmpv4_hdr_t*)(packet + ip_len + l2len);
+        }
+        icmp_hdr = (icmpv4_hdr_t *)(packet + ip_len + l2len);
         entry.src_port = icmp_hdr->icmp_type;
         entry.dst_port = icmp_hdr->icmp_code;
         break;
+    }
     default:
         entry.src_port = 0;
         entry.dst_port = 0;

+ 3 - 2
src/common/flows.h

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -38,4 +38,5 @@ flow_entry_type_t flow_decode(flow_hash_table_t *fht,
                               const struct pcap_pkthdr *pkthdr,
                               const u_char *pktdata,
                               const int datalink,
-                              const int expiry);
+                              const int expiry,
+                              COUNTER packetnum);

+ 135 - 36
src/common/get.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -41,8 +41,8 @@ extern const char pcap_version[];
 static void *get_ipv6_next(struct tcpr_ipv6_ext_hdr_base *exthdr, const u_char *end_ptr);
 
 /**
- * Depending on what version of libpcap/WinPcap there are different ways to get
- * the version of the libpcap/WinPcap library.  This presents a unified way to
+ * Depending on what version of libpcap there are different ways to get
+ * the version of the libpcap library.  This presents a unified way to
  * get that information.
  */
 const char *
@@ -103,8 +103,12 @@ parse_mpls(const u_char *pktdata, uint32_t datalen, uint16_t *next_protocol, uin
 
     /* move over MPLS labels until we get to the last one */
     while (!bos) {
-        if (pktdata + len + sizeof(*mpls_label) > end_ptr)
+        if (pktdata + len + sizeof(*mpls_label) > end_ptr) {
+            warnx("parse_mpls: Need at least %zu bytes for MPLS header but only %u available",
+                  sizeof(*mpls_label) + len,
+                  datalen);
             return -1;
+        }
 
         mpls_label = (struct tcpr_mpls_label *)(pktdata + len);
         len += sizeof(*mpls_label);
@@ -117,8 +121,12 @@ parse_mpls(const u_char *pktdata, uint32_t datalen, uint16_t *next_protocol, uin
         }
     }
 
-    if ((u_char *)(mpls_label + 1) + 1 > end_ptr)
+    if ((u_char *)(mpls_label + 1) + 1 > end_ptr) {
+        warnx("parse_mpls: Need at least %zu bytes for MPLS label but only %u available",
+              sizeof(*mpls_label) + 1,
+              datalen);
         return -1;
+    }
 
     first_nibble = *((u_char *)(mpls_label + 1)) >> 4;
     switch (first_nibble) {
@@ -132,8 +140,12 @@ parse_mpls(const u_char *pktdata, uint32_t datalen, uint16_t *next_protocol, uin
         /* EoMPLS - jump over PW Ethernet Control Word and handle
          * inner Ethernet header
          */
-        if (pktdata + len + 4 + sizeof(*eth_hdr) > end_ptr)
+        if (pktdata + len + 4 + sizeof(*eth_hdr) > end_ptr) {
+            warnx("parse_mpls: Need at least %zu bytes for EoMPLS header but only %u available",
+                  sizeof(*eth_hdr) + len + 4,
+                  datalen);
             return -1;
+        }
 
         len += 4;
         *l2offset = len;
@@ -142,7 +154,7 @@ parse_mpls(const u_char *pktdata, uint32_t datalen, uint16_t *next_protocol, uin
         *next_protocol = ntohs(eth_hdr->ether_type);
         break;
     default:
-        /* suspect Generic Associated Channel Header */
+        warn("parse_mpls:suspect Generic Associated Channel Header");
         return -1;
     }
 
@@ -165,9 +177,10 @@ int
 parse_vlan(const u_char *pktdata, uint32_t datalen, uint16_t *next_protocol, uint32_t *l2len)
 {
     vlan_hdr_t *vlan_hdr;
-    if ((size_t)datalen < *l2len + sizeof(*vlan_hdr))
+    if ((size_t)datalen < *l2len + sizeof(*vlan_hdr)) {
+        warnx("parse_vlan: Need at least %zu bytes for VLAN header but only %u available", sizeof(*vlan_hdr), datalen);
         return -1;
-
+    }
     vlan_hdr = (vlan_hdr_t *)(pktdata + *l2len);
     *next_protocol = ntohs(vlan_hdr->vlan_tpid);
     *l2len += sizeof(vlan_hdr_t);
@@ -196,8 +209,15 @@ parse_metadata(const u_char *pktdata,
                uint32_t *vlan_offset)
 {
     bool done = false;
-    int res = 0;
-    while (!done && res == 0) {
+    assert(next_protocol);
+    assert(l2len);
+    assert(l2offset);
+    assert(vlan_offset);
+
+    if (!pktdata || !datalen)
+        errx(-1, "parse_metadata: invalid L2 parameters: pktdata=0x%p len=%d", pktdata, datalen);
+
+    while (!done) {
         switch (*next_protocol) {
         case ETHERTYPE_VLAN:
         case ETHERTYPE_Q_IN_Q:
@@ -205,18 +225,22 @@ parse_metadata(const u_char *pktdata,
             if (*vlan_offset == 0)
                 *vlan_offset = *l2len;
 
-            res = parse_vlan(pktdata, datalen, next_protocol, l2len);
+            if (parse_vlan(pktdata, datalen, next_protocol, l2len))
+                return -1;
+
             break;
         case ETHERTYPE_MPLS:
         case ETHERTYPE_MPLS_MULTI:
-            res = parse_mpls(pktdata, datalen, next_protocol, l2len, l2offset);
+            if (parse_mpls(pktdata, datalen, next_protocol, l2len, l2offset))
+                return -1;
+
             break;
         default:
             done = true;
         }
     }
 
-    return res;
+    return 0;
 }
 
 /*
@@ -266,19 +290,29 @@ get_l2len_protocol(const u_char *pktdata,
             *protocol = ETHERTYPE_IP6;
         break;
     case DLT_JUNIPER_ETHER:
-        if (datalen < 4)
+        if (datalen < 4) {
+            warnx("%s (0x%x): Need at least 4 bytes for DLT_JUNIPER_ETHER but only %u available",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  datalen);
             return -1;
+        }
 
         if (memcmp(pktdata, JUNIPER_PCAP_MAGIC, 3) != 0) {
-            warnx("No Magic Number found during protocol lookup: %s (0x%x)",
+            warnx("%s (0x%x): No JUNIPER_PCAP_MAGIC Magic Number found during protocol lookup",
                   pcap_datalink_val_to_description(datalink),
                   datalink);
             return -1;
         }
 
         if ((pktdata[3] & JUNIPER_FLAG_EXT) == JUNIPER_FLAG_EXT) {
-            if (datalen < 6)
+            if (datalen < 6) {
+                warnx("%s (0x%x): Need at least 6 bytes for JUNIPER_FLAG_EXT but only %u available",
+                      pcap_datalink_val_to_description(datalink),
+                      datalink,
+                      datalen);
                 return -1;
+            }
 
             *l2offset = ntohs(*((uint16_t *)&pktdata[4]));
             *l2offset += 6; /* MGC + flags + ext_total_len */
@@ -289,8 +323,15 @@ get_l2len_protocol(const u_char *pktdata,
         if ((pktdata[3] & JUNIPER_FLAG_NO_L2) == JUNIPER_FLAG_NO_L2) {
             /* no L2 header present - *l2offset is actually IP offset */
             uint32_t ip_hdr_offset = *l2offset;
-            if (datalen < ip_hdr_offset + 1)
+            uint32_t hdrSpaceNeeded = ip_hdr_offset + 1;
+            if (datalen < hdrSpaceNeeded) {
+                warnx("%s (0x%x): Need at least %u bytes for JUNIPER_FLAG_NO_L2 but only %u available",
+                      pcap_datalink_val_to_description(datalink),
+                      hdrSpaceNeeded,
+                      datalink,
+                      datalen);
                 return -1;
+            }
 
             if ((pktdata[ip_hdr_offset] >> 4) == 4)
                 *protocol = ETHERTYPE_IP;
@@ -306,36 +347,46 @@ get_l2len_protocol(const u_char *pktdata,
         uint16_t ether_type;
         uint32_t l2_net_off = sizeof(*eth_hdr) + *l2offset;
 
-        if (datalen <= l2_net_off)
+        if (datalen <= l2_net_off + 4) {
+            warnx("%s (0x%x): Need at least %u bytes for DLT_EN10MB but only %u available",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  l2_net_off + 4,
+                  datalen);
             return -1;
+        }
 
         eth_hdr = (eth_hdr_t *)(pktdata + *l2offset);
         ether_type = ntohs(eth_hdr->ether_type);
         if (parse_metadata(pktdata, datalen, &ether_type, &l2_net_off, l2offset, vlan_offset))
             return -1;
 
-        if (datalen <= l2_net_off)
-            return -1;
-
         *l2len = l2_net_off;
-        if (ether_type > 1500) {
+        if (ether_type >= 1536) {
             /* Ethernet II frame - return in host order */
             *protocol = ether_type;
+        } else if (ether_type > 1500) {
+            warnx("%s (0x%x): unsupported 802.3 length %u",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  ether_type);
+            return -1;
         } else {
             /* 803.3 frame */
-            if ((pktdata[l2_net_off] >> 4) == 4)
-                *protocol = ETHERTYPE_IP;
-            else if ((pktdata[l2_net_off] >> 4) == 6)
-                *protocol = ETHERTYPE_IP6;
-            else
-                /* unsupported 802.3 protocol */
-                return -1;
+            /* we don't modify 802.3 protocols */
+            return -1;
         }
         break;
     }
     case DLT_PPP_SERIAL:
-        if ((size_t)datalen < sizeof(struct tcpr_pppserial_hdr))
+        if ((size_t)datalen < sizeof(struct tcpr_pppserial_hdr)) {
+            warnx("%s (0x%x): Need at least %zu bytes for DLT_PPP_SERIAL but only %u available",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  sizeof(struct tcpr_pppserial_hdr),
+                  datalen);
             return -1;
+        }
 
         struct tcpr_pppserial_hdr *ppp = (struct tcpr_pppserial_hdr *)pktdata;
         *l2len = sizeof(*ppp);
@@ -346,21 +397,47 @@ get_l2len_protocol(const u_char *pktdata,
 
         break;
     case DLT_C_HDLC:
-        if (datalen < CISCO_HDLC_LEN)
+        if (datalen < CISCO_HDLC_LEN) {
+            warnx("%s (0x%x): Need at least %u bytes for DLT_C_HDLC but only %u available",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  CISCO_HDLC_LEN,
+                  datalen);
             return -1;
+        }
 
         hdlc_hdr_t *hdlc_hdr = (hdlc_hdr_t *)pktdata;
         *l2len = sizeof(*hdlc_hdr);
         *protocol = ntohs(hdlc_hdr->protocol);
         break;
     case DLT_LINUX_SLL:
-        if (datalen < SLL_HDR_LEN)
+        if (datalen < SLL_HDR_LEN) {
+            warnx("%s (0x%x): Need at least %u bytes for DLT_LINUX_SLL but only %u available",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  SLL_HDR_LEN,
+                  datalen);
             return -1;
+        }
 
+        *l2len = SLL_HDR_LEN;
         sll_hdr_t *sll_hdr = (sll_hdr_t *)pktdata;
-        *l2len = sizeof(*sll_hdr);
         *protocol = ntohs(sll_hdr->sll_protocol);
         break;
+    case DLT_LINUX_SLL2:
+        if (datalen < SLL2_HDR_LEN) {
+            warnx("%s (0x%x): Need at least %u bytes for DLT_LINUX_SLL2 but only %u available",
+                  pcap_datalink_val_to_description(datalink),
+                  datalink,
+                  SLL2_HDR_LEN,
+                  datalen);
+            return -1;
+        }
+
+        *l2len = SLL2_HDR_LEN;
+        sll2_hdr_t *sll2_hdr = (sll2_hdr_t *)pktdata;
+        *protocol = ntohs(sll2_hdr->sll2_protocol);
+        break;
     default:
         errx(-1,
              "Unable to process unsupported DLT type: %s (0x%x)",
@@ -593,9 +670,25 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const u_char *end_ptr)
             break;
 
         /*
-         * Can't handle.  Unparsable IPv6 fragment/encrypted data
+         * handle (unparsable) IPv6 fragment data
          */
         case TCPR_IPV6_NH_FRAGMENT:
+            // next points to l4 data
+            dbgx(3, "Go deeper due to fragment extension header 0x%02X", proto);
+            exthdr = get_ipv6_next(next, end_ptr);
+            if ((exthdr == NULL) || ((u_char *)exthdr > end_ptr)) {
+                next = NULL;
+                done = true;
+                break;
+            }
+            proto = exthdr->ip_nh;
+            next = exthdr;
+            // done = true;
+            break;
+
+        /*
+         * Can't handle.  Unparsable IPv6 encrypted data
+         */
         case TCPR_IPV6_NH_ESP:
             next = NULL;
             done = true;
@@ -605,9 +698,11 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const u_char *end_ptr)
          * no further processing, either TCP, UDP, ICMP, etc...
          */
         default:
-            if (proto != ip6_hdr->ip_nh) {
+            if (proto != ip6_hdr->ip_nh && next) {
                 dbgx(3, "Returning byte offset of this ext header: %u", IPV6_EXTLEN_TO_BYTES(next->ip_len));
                 next = (void *)((u_char *)next + IPV6_EXTLEN_TO_BYTES(next->ip_len));
+                if ((u_char*)next > end_ptr)
+                    return NULL;
             } else {
                 dbgx(3, "%s", "Returning end of IPv6 Header");
             }
@@ -663,6 +758,10 @@ get_ipv6_next(struct tcpr_ipv6_ext_hdr_base *exthdr, const u_char *end_ptr)
     case TCPR_IPV6_NH_HBH:
     case TCPR_IPV6_NH_AH:
         extlen = IPV6_EXTLEN_TO_BYTES(exthdr->ip_len);
+        if (extlen == 0) {
+            dbg(3, "Malformed IPv6 extension header...");
+            return NULL;
+        }
         dbgx(3,
              "Looks like we're an ext header (0x%hhx).  Jumping %u bytes"
              " to the next",

+ 1 - 1
src/common/get.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 1 - 1
src/common/git_version.c

@@ -1,4 +1,4 @@
-const char GIT_Version[] = "git:v4.4.4";
+const char GIT_Version[] = "git:v4.5.1";
 const char *git_version(void) {
     return GIT_Version;
 }

+ 1 - 1
src/common/interface.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common/interface.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 25 - 24
src/common/list.c

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -44,6 +44,21 @@ new_list()
     return (newlist);
 }
 
+static void
+add_to_list(tcpr_list_t *list_ptr, const char *first, const char *second)
+{
+    list_ptr->min = strtoull(first, NULL, 0);
+    if (second != NULL) {
+        if (second[0] == '\0') {
+            list_ptr->max = 0;
+        } else {
+            list_ptr->max = strtoull(second, NULL, 0);
+        }
+    } else {
+        list_ptr->max = list_ptr->min;
+    }
+}
+
 /**
  * Processes a string (ourstr) containing the list in human readable
  * format and places the data in **list and finally returns 1 for
@@ -57,7 +72,7 @@ parse_list(tcpr_list_t **listdata, char *ourstr)
     char *first, *second;
     int rcode;
     regex_t preg;
-    char regex[] = "^[0-9]+(-[0-9]+)?$";
+    char regex[] = "^[0-9]+(-([0-9]+|\\s*))?$";
     char *token = NULL;
     u_int i;
 
@@ -91,12 +106,7 @@ parse_list(tcpr_list_t **listdata, char *ourstr)
         }
     }
 
-    list_ptr->min = strtoull(first, NULL, 0);
-    if (second != NULL) {
-        list_ptr->max = strtoull(second, NULL, 0);
-    } else {
-        list_ptr->max = list_ptr->min;
-    }
+    add_to_list(list_ptr, first, second);
 
     while (1) {
         this = strtok_r(NULL, ",", &token);
@@ -123,12 +133,7 @@ parse_list(tcpr_list_t **listdata, char *ourstr)
             }
         }
 
-        listcur->min = strtoull(first, NULL, 0);
-        if (second != NULL) {
-            listcur->max = strtoull(second, NULL, 0);
-        } else {
-            listcur->max = listcur->min;
-        }
+        add_to_list(listcur, first, second);
     }
 
     regfree(&preg);
@@ -144,10 +149,8 @@ tcpr_dir_t
 check_list(tcpr_list_t *list, COUNTER value)
 {
     tcpr_list_t *current;
-    current = list;
-
-    do {
-        if ((current->min != 0) && (current->max != 0)) {
+    for (current = list; current; current = current->next) {
+        if (current->min != 0 && current->max != 0) {
             if ((value >= current->min) && (value <= current->max))
                 return 1;
         } else if (current->min == 0) {
@@ -157,12 +160,7 @@ check_list(tcpr_list_t *list, COUNTER value)
             if (value >= current->min)
                 return 1;
         }
-
-        if (current->next != NULL)
-            current = current->next;
-        else
-            current = NULL;
-    } while (current != NULL);
+    }
 
     return 0;
 }
@@ -173,6 +171,9 @@ check_list(tcpr_list_t *list, COUNTER value)
 void
 free_list(tcpr_list_t *list)
 {
+    if (list == NULL)
+        return;
+
     /* recursively go down the list */
     if (list->next != NULL)
         free_list(list->next);

+ 1 - 1
src/common/list.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common/mac.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common/mac.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 1 - 1
src/common/pcap_dlt.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 321 - 99
src/common/sendpacket.c

@@ -27,6 +27,7 @@
  * injection method, then by all means add it here (and send me a patch).
  *
  * Anyways, long story short, for now the order of preference is:
+ * 0. pcap_dump
  * 1. TX_RING
  * 2. PF_PACKET
  * 3. BPF
@@ -63,6 +64,7 @@
 #undef HAVE_PCAP_INJECT
 #undef HAVE_PCAP_SENDPACKET
 #undef HAVE_BPF
+#undef HAVE_LIBXDP
 #endif
 
 #ifdef FORCE_INJECT_PF_PACKET
@@ -71,6 +73,7 @@
 #undef HAVE_PCAP_INJECT
 #undef HAVE_PCAP_SENDPACKET
 #undef HAVE_BPF
+#undef HAVE_LIBXDP
 #endif
 
 #ifdef FORCE_INJECT_LIBDNET
@@ -79,6 +82,7 @@
 #undef HAVE_PCAP_INJECT
 #undef HAVE_PCAP_SENDPACKET
 #undef HAVE_BPF
+#undef HAVE_LIBXDP
 #endif
 
 #ifdef FORCE_INJECT_BPF
@@ -87,6 +91,7 @@
 #undef HAVE_PCAP_INJECT
 #undef HAVE_PCAP_SENDPACKET
 #undef HAVE_PF_PACKET
+#undef HAVE_LIBXDP
 #endif
 
 #ifdef FORCE_INJECT_PCAP_INJECT
@@ -95,6 +100,7 @@
 #undef HAVE_PCAP_SENDPACKET
 #undef HAVE_BPF
 #undef HAVE_PF_PACKET
+#undef HAVE_LIBXDP
 #endif
 
 #ifdef FORCE_INJECT_PCAP_SENDPACKET
@@ -103,6 +109,16 @@
 #undef HAVE_PCAP_INJECT
 #undef HAVE_BPF
 #undef HAVE_PF_PACKET
+#undef HAVE_LIBXDP
+#endif
+
+#ifdef FORCE_INJECT_LIBXDP
+#undef HAVE_TX_RING
+#undef HAVE_LIBDNET
+#undef HAVE_PF_PACKET
+#undef HAVE_PCAP_INJECT
+#undef HAVE_PCAP_SENDPACKET
+#undef HAVE_BPF
 #endif
 
 #if (defined HAVE_WINPCAP && defined HAVE_PCAP_INJECT)
@@ -110,16 +126,13 @@
 #endif
 
 #if !defined HAVE_PCAP_INJECT && !defined HAVE_PCAP_SENDPACKET && !defined HAVE_LIBDNET && !defined HAVE_PF_PACKET &&  \
-        !defined HAVE_BPF && !defined TX_RING
-#error You need pcap_inject() or pcap_sendpacket() from libpcap, libdnet, Linux's PF_PACKET/TX_RING or *BSD's BPF
+        !defined HAVE_BPF && !defined TX_RING && !defined HAVE_LIBXDP
+#error You need pcap_inject() or pcap_sendpacket() from libpcap, libdnet, Linux's PF_PACKET/TX_RING/AF_XDP with libxdp or *BSD's BPF
 #endif
 
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
-#ifdef HAVE_SYS_SYSCTL_H
-#include <sys/sysctl.h>
-#endif
 #ifdef HAVE_NET_ROUTE_H
 #include <net/route.h>
 #endif
@@ -211,7 +224,16 @@ static struct tcpr_ether_addr *sendpacket_get_hwaddr_pcap(sendpacket_t *) _U_;
 #undef INJECT_METHOD
 #define INJECT_METHOD "pcap_sendpacket()"
 #endif
-
+#ifdef HAVE_LIBXDP
+#include <sys/mman.h>
+static sendpacket_t *sendpacket_open_xsk(const char *, char *) _U_;
+static struct tcpr_ether_addr *sendpacket_get_hwaddr_libxdp(sendpacket_t *);
+#endif
+#if defined HAVE_LIBXDP && !defined INJECT_METHOD
+#undef INJECT_METHOD
+#define INJECT_METHOD "xsk_ring_prod_submit()"
+#endif
+static sendpacket_t *sendpacket_open_pcap_dump(const char *, char *) _U_;
 static void sendpacket_seterr(sendpacket_t *sp, const char *fmt, ...);
 static sendpacket_t *sendpacket_open_khial(const char *, char *) _U_;
 static struct tcpr_ether_addr *sendpacket_get_hwaddr_khial(sendpacket_t *) _U_;
@@ -237,7 +259,10 @@ sendpacket(sendpacket_t *sp, const u_char *data, size_t len, struct pcap_pkthdr
     static const size_t buffer_payload_size = sizeof(buffer) + sizeof(struct pcap_pkthdr);
 
     assert(sp);
+#ifndef HAVE_LIBXDP
+    // In case of XDP packet processing we are storing data in sp->packet_processing->xdp_descs
     assert(data);
+#endif
 
     if (len == 0)
         return -1;
@@ -434,6 +459,11 @@ TRY_SEND_AGAIN:
 
         break;
 
+    case SP_TYPE_LIBPCAP_DUMP:
+        pcap_dump((u_char *)sp->handle.dump.dump, pkthdr, data);
+        retcode = len;
+        break;
+
     case SP_TYPE_NETMAP:
 #ifdef HAVE_NETMAP
         retcode = sendpacket_send_netmap(sp, data, len);
@@ -452,7 +482,18 @@ TRY_SEND_AGAIN:
         }
 #endif /* HAVE_NETMAP */
         break;
-
+    case SP_TYPE_LIBXDP:
+#ifdef HAVE_LIBXDP
+        retcode = len;
+        xsk_ring_prod__submit(&(sp->xsk_info->tx), sp->pckt_count); // submit all packets at once
+        sp->xsk_info->ring_stats.tx_npkts += sp->pckt_count;
+        sp->xsk_info->outstanding_tx += sp->pckt_count;
+        while (sp->xsk_info->outstanding_tx != 0) {
+            complete_tx_only(sp);
+        }
+        sp->sent += sp->pckt_count;
+#endif
+        break;
     default:
         errx(-1, "Unsupported sp->handle_type = %d", sp->handle_type);
     } /* end case */
@@ -465,8 +506,15 @@ TRY_SEND_AGAIN:
         sendpacket_seterr(sp, "Only able to write %d bytes out of %lu bytes total", retcode, len);
         sp->trunc_packets++;
     } else {
+#ifndef HAVE_LIBXDP
         sp->bytes_sent += len;
         sp->sent++;
+#else
+        if (sp->handle_type != SP_TYPE_LIBXDP) {
+            sp->bytes_sent += len;
+            sp->sent++;
+        }
+#endif
     }
     return retcode;
 }
@@ -483,10 +531,6 @@ sendpacket_open(const char *device,
                 sendpacket_type_t sendpacket_type _U_,
                 void *arg _U_)
 {
-#ifdef HAVE_TUNTAP
-    char sys_dev_dir[128];
-    bool device_exists;
-#endif
     sendpacket_t *sp;
     struct stat sdata;
 
@@ -495,53 +539,57 @@ sendpacket_open(const char *device,
 
     errbuf[0] = '\0';
 
-#ifdef HAVE_TUNTAP
-    snprintf(sys_dev_dir, sizeof(sys_dev_dir), "/sys/class/net/%s/", device);
-    device_exists = access(sys_dev_dir, R_OK) == 0;
-#endif
-
-    /* khial is universal */
-    if (stat(device, &sdata) == 0) {
-        if (((sdata.st_mode & S_IFMT) == S_IFCHR)) {
-            sp = sendpacket_open_khial(device, errbuf);
-
-        } else {
-            switch (sdata.st_mode & S_IFMT) {
-            case S_IFBLK:
-                errx(-1, "\"%s\" is a block device and is not a valid Tcpreplay device", device);
-            case S_IFDIR:
-                errx(-1, "\"%s\" is a directory and is not a valid Tcpreplay device", device);
-            case S_IFIFO:
-                errx(-1, "\"%s\" is a FIFO and is not a valid Tcpreplay device", device);
-            case S_IFLNK:
-                errx(-1, "\"%s\" is a symbolic link and is not a valid Tcpreplay device", device);
-            case S_IFREG:
-                errx(-1, "\"%s\" is a file and is not a valid Tcpreplay device", device);
-            default:
-                errx(-1, "\"%s\" is not a valid Tcpreplay device", device);
+    if (sendpacket_type == SP_TYPE_LIBPCAP_DUMP) {
+        sp = sendpacket_open_pcap_dump(device, errbuf);
+    } else {
+        /* khial is universal */
+        if (stat(device, &sdata) == 0) {
+            if (((sdata.st_mode & S_IFMT) == S_IFCHR)) {
+                sp = sendpacket_open_khial(device, errbuf);
+
+            } else {
+                switch (sdata.st_mode & S_IFMT) {
+                case S_IFBLK:
+                    errx(-1, "\"%s\" is a block device and is not a valid Tcpreplay device", device);
+                case S_IFDIR:
+                    errx(-1, "\"%s\" is a directory and is not a valid Tcpreplay device", device);
+                case S_IFIFO:
+                    errx(-1, "\"%s\" is a FIFO and is not a valid Tcpreplay device", device);
+                case S_IFLNK:
+                    errx(-1, "\"%s\" is a symbolic link and is not a valid Tcpreplay device", device);
+                case S_IFREG:
+                    errx(-1, "\"%s\" is a file and is not a valid Tcpreplay device", device);
+                default:
+                    errx(-1, "\"%s\" is not a valid Tcpreplay device", device);
+                }
             }
-        }
 #ifdef HAVE_TUNTAP
-    } else if (strncmp(device, "tap", 3) == 0 && !device_exists) {
-        sp = sendpacket_open_tuntap(device, errbuf);
+        } else if (strncmp(device, "tap", 3) == 0) {
+            sp = sendpacket_open_tuntap(device, errbuf);
 #endif
-    } else {
+        } else {
 #ifdef HAVE_NETMAP
-        if (sendpacket_type == SP_TYPE_NETMAP)
-            sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg);
-        else
+            if (sendpacket_type == SP_TYPE_NETMAP)
+                sp = (sendpacket_t *)sendpacket_open_netmap(device, errbuf, arg);
+            else
+#endif
+#ifdef HAVE_LIBXDP
+            if (sendpacket_type == SP_TYPE_LIBXDP)
+                sp = sendpacket_open_xsk(device, errbuf);
+            else
 #endif
 #if defined HAVE_PF_PACKET
-            sp = sendpacket_open_pf(device, errbuf);
+                sp = sendpacket_open_pf(device, errbuf);
 #elif defined HAVE_BPF
-        sp = sendpacket_open_bpf(device, errbuf);
+                sp = sendpacket_open_bpf(device, errbuf);
 #elif defined HAVE_LIBDNET
-        sp = sendpacket_open_libdnet(device, errbuf);
+                sp = sendpacket_open_libdnet(device, errbuf);
 #elif (defined HAVE_PCAP_INJECT || defined HAVE_PCAP_SENDPACKET)
-        sp = sendpacket_open_pcap(device, errbuf);
+                sp = sendpacket_open_pcap(device, errbuf);
 #else
 #error "No defined packet injection method for sendpacket_open()"
 #endif
+        }
     }
 
     if (sp) {
@@ -631,6 +679,11 @@ sendpacket_close(sendpacket_t *sp)
 #endif
         break;
 
+    case SP_TYPE_LIBPCAP_DUMP:
+        pcap_dump_close(sp->handle.dump.dump);
+        pcap_close(sp->handle.dump.pcap);
+        break;
+
     case SP_TYPE_LIBDNET:
 #ifdef HAVE_LIBDNET
         eth_close(sp->handle.ldnet);
@@ -649,6 +702,13 @@ sendpacket_close(sendpacket_t *sp)
         close(sp->handle.fd);
 #endif
         break;
+    case SP_TYPE_LIBXDP:
+#ifdef HAVE_LIBXDP
+        close(sp->handle.fd);
+        safe_free(sp->xsk_info);
+        safe_free(sp->umem_info);
+#endif
+        break;
     case SP_TYPE_NONE:
         err(-1, "no injector selected!");
     }
@@ -671,9 +731,14 @@ sendpacket_get_hwaddr(sendpacket_t *sp)
 
     if (sp->handle_type == SP_TYPE_KHIAL) {
         addr = sendpacket_get_hwaddr_khial(sp);
+    } else if (sp->handle_type == SP_TYPE_LIBPCAP_DUMP) {
+        sendpacket_seterr(sp, "Error: sendpacket_get_hwaddr() not yet supported for pcap dump");
+        return NULL;
     } else {
 #if defined HAVE_PF_PACKET
         addr = sendpacket_get_hwaddr_pf(sp);
+#elif defined HAVE_LIBXDP
+        addr = sendpacket_get_hwaddr_libxdp(sp);
 #elif defined HAVE_BPF
         addr = sendpacket_get_hwaddr_bpf(sp);
 #elif defined HAVE_LIBDNET
@@ -767,6 +832,37 @@ sendpacket_get_hwaddr_pcap(sendpacket_t *sp)
 }
 #endif /* HAVE_PCAP_INJECT || HAVE_PCAP_SENDPACKET */
 
+/**
+ * Inner sendpacket_open() method for using libpcap
+ */
+static sendpacket_t *
+sendpacket_open_pcap_dump(const char *device, char *errbuf)
+{
+    pcap_t *pcap;
+    pcap_dumper_t* dump;
+    sendpacket_t *sp;
+
+    assert(device);
+    assert(errbuf);
+
+    dbg(1, "sendpacket: using Libpcap");
+
+    pcap = pcap_open_dead(DLT_EN10MB, MAX_SNAPLEN);
+    if ((dump = pcap_dump_open(pcap, device)) == NULL){
+        char* err_msg = pcap_geterr(pcap);
+        strlcpy(errbuf, err_msg, PCAP_ERRBUF_SIZE);
+        pcap_close(pcap);
+        return NULL;
+    }
+
+    sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
+    strlcpy(sp->device, device, sizeof(sp->device));
+    sp->handle.dump.pcap = pcap;
+    sp->handle.dump.dump = dump;
+    sp->handle_type = SP_TYPE_LIBPCAP_DUMP;
+    return sp;
+}
+
 #if defined HAVE_LIBDNET && !defined HAVE_PF_PACKET && !defined HAVE_BPF
 /**
  * Inner sendpacket_open() method for using libdnet
@@ -1066,7 +1162,7 @@ sendpacket_open_bpf(const char *device, char *errbuf)
 {
     sendpacket_t *sp;
     char bpf_dev[16];
-    int dev, mysocket, link_offset, link_type;
+    int dev, mysocket;
     struct ifreq ifr;
     struct bpf_version bv;
     u_int v;
@@ -1134,43 +1230,10 @@ sendpacket_open_bpf(const char *device, char *errbuf)
     }
 #endif
 
-    /* assign link type and offset */
-    switch (v) {
-    case DLT_SLIP:
-        link_offset = 0x10;
-        break;
-    case DLT_RAW:
-        link_offset = 0x0;
-        break;
-    case DLT_PPP:
-        link_offset = 0x04;
-        break;
-    case DLT_EN10MB:
-    default: /* default to Ethernet */
-        link_offset = 0xe;
-        break;
-    }
-#if _BSDI_VERSION - 0 > 199510
-    switch (v) {
-    case DLT_SLIP:
-        v = DLT_SLIP_BSDOS;
-        link_offset = 0x10;
-        break;
-    case DLT_PPP:
-        v = DLT_PPP_BSDOS;
-        link_offset = 0x04;
-        break;
-    }
-#endif
-
-    link_type = v;
-
     /* allocate our sp handle, and return it */
     sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
     strlcpy(sp->device, device, sizeof(sp->device));
     sp->handle.fd = mysocket;
-    // sp->link_type = link_type;
-    // sp->link_offset = link_offset;
     sp->handle_type = SP_TYPE_BPF;
 
     return sp;
@@ -1236,30 +1299,36 @@ sendpacket_get_dlt(sendpacket_t *sp)
 {
     int dlt = DLT_EN10MB;
 
-    if (sp->handle_type == SP_TYPE_KHIAL || sp->handle_type == SP_TYPE_NETMAP || sp->handle_type == SP_TYPE_TUNTAP) {
+    switch (sp->handle_type) {
+    case SP_TYPE_KHIAL:
+    case SP_TYPE_NETMAP:
+    case SP_TYPE_TUNTAP:
+    case SP_TYPE_LIBXDP:
+    case SP_TYPE_LIBPCAP_DUMP:
         /* always EN10MB */
-    } else {
-#if defined HAVE_BPF
-        int rcode;
+        return dlt;
+    default:;
+    }
 
-        if ((rcode = ioctl(sp->handle.fd, BIOCGDLT, &dlt)) < 0) {
-            warnx("Unable to get DLT value for BPF device (%s): %s", sp->device, strerror(errno));
-            return (-1);
-        }
+#if defined HAVE_BPF
+    if ((ioctl(sp->handle.fd, BIOCGDLT, &dlt)) < 0) {
+        warnx("Unable to get DLT value for BPF device (%s): %s", sp->device, strerror(errno));
+        return (-1);
+    }
 #elif defined HAVE_PF_PACKET || defined HAVE_LIBDNET
-        /* use libpcap to get dlt */
-        pcap_t *pcap;
-        char errbuf[PCAP_ERRBUF_SIZE];
-        if ((pcap = pcap_open_live(sp->device, 65535, 0, 0, errbuf)) == NULL) {
-            warnx("Unable to get DLT value for %s: %s", sp->device, errbuf);
-            return (-1);
-        }
-        dlt = pcap_datalink(pcap);
-        pcap_close(pcap);
+    /* use libpcap to get dlt */
+    pcap_t *pcap;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    if ((pcap = pcap_open_live(sp->device, 65535, 0, 0, errbuf)) == NULL) {
+        warnx("Unable to get DLT value for %s: %s", sp->device, errbuf);
+        return (-1);
+    }
+    dlt = pcap_datalink(pcap);
+    pcap_close(pcap);
 #elif defined HAVE_PCAP_SENDPACKET || defined HAVE_PCAP_INJECT
-        dlt = pcap_datalink(sp->handle.pcap);
+    dlt = pcap_datalink(sp->handle.pcap);
 #endif
-    }
+
     return dlt;
 }
 
@@ -1327,3 +1396,156 @@ sendpacket_abort(sendpacket_t *sp)
 
     sp->abort = true;
 }
+#ifdef HAVE_LIBXDP
+static struct xsk_socket_info *
+xsk_configure_socket(struct xsk_umem_info *umem, struct xsk_socket_config *cfg, int queue_id, const char *device)
+{
+    struct xsk_socket_info *xsk;
+    struct xsk_ring_cons *rxr = NULL;
+    int ret;
+
+    xsk = (struct xsk_socket_info *)safe_malloc(sizeof(struct xsk_socket_info));
+    xsk->umem = umem;
+    ret = xsk_socket__create(&xsk->xsk, device, queue_id, umem->umem, rxr, &xsk->tx, cfg);
+    if (ret) {
+        return NULL;
+    }
+
+    memset(&xsk->app_stats, 0, sizeof(xsk->app_stats));
+
+    return xsk;
+}
+
+static sendpacket_t *
+sendpacket_open_xsk(const char *device, char *errbuf)
+{
+    sendpacket_t *sp;
+
+    assert(device);
+    assert(errbuf);
+
+    int nb_of_frames = 4096;
+    int frame_size = 4096;
+    int nb_of_completion_queue_desc = 4096;
+    int nb_of_fill_queue_desc = 4096;
+    struct xsk_umem_info *umem_info =
+            create_umem_area(nb_of_frames, frame_size, nb_of_completion_queue_desc, nb_of_fill_queue_desc);
+    if (umem_info == NULL) {
+        return NULL;
+    }
+
+    int nb_of_tx_queue_desc = 4096;
+    int nb_of_rx_queue_desc = 4096;
+    u_int32_t queue_id = 0;
+    struct xsk_socket_info *xsk_info =
+            create_xsk_socket(umem_info, nb_of_tx_queue_desc, nb_of_rx_queue_desc, device, queue_id, errbuf);
+    if (xsk_info == NULL) {
+        return NULL;
+    }
+
+    sp = (sendpacket_t *)safe_malloc(sizeof(sendpacket_t));
+    strlcpy(sp->device, device, sizeof(sp->device));
+    sp->handle.fd = xsk_info->xsk->fd;
+    sp->handle_type = SP_TYPE_LIBXDP;
+    sp->xsk_info = xsk_info;
+    sp->umem_info = umem_info;
+    sp->frame_size = frame_size;
+    sp->tx_size = nb_of_tx_queue_desc;
+    return sp;
+}
+
+struct xsk_umem_info *
+create_umem_area(int nb_of_frames, int frame_size, int nb_of_completion_queue_descs, int nb_of_fill_queue_descs)
+{
+    int umem_size = nb_of_frames * frame_size;
+    struct xsk_umem_info *umem;
+    void *umem_area = NULL;
+    struct xsk_umem_config cfg = {/* We recommend that you set the fill ring size >= HW RX ring size +
+                                   * AF_XDP RX ring size. Make sure you fill up the fill ring
+                                   * with buffers at regular intervals, and you will with this setting
+                                   * avoid allocation failures in the driver. These are usually quite
+                                   * expensive since drivers have not been written to assume that
+                                   * allocation failures are common. For regular sockets, kernel
+                                   * allocated memory is used that only runs out in OOM situations
+                                   * that should be rare.
+                                   */
+                                  .fill_size = nb_of_fill_queue_descs * 2,
+                                  .comp_size = nb_of_completion_queue_descs,
+                                  .frame_size = frame_size,
+                                  .frame_headroom = 0,
+                                  .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG};
+    umem = (struct xsk_umem_info *)safe_malloc(sizeof(struct xsk_umem_info));
+    if (posix_memalign(&umem_area,
+                       getpagesize(), /* PAGE_SIZE aligned */
+                       umem_size)) {
+        fprintf(stderr, "ERROR: Can't allocate buffer memory \"%s\"\n", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    int ret = xsk_umem__create(&umem->umem, umem_area, umem_size, &umem->fq, &umem->cq, &cfg);
+    umem->buffer = umem_area;
+    if (ret != 0) {
+        return NULL;
+    }
+    return umem;
+}
+
+struct xsk_socket_info *
+create_xsk_socket(struct xsk_umem_info *umem_info,
+                  int nb_of_tx_queue_desc,
+                  int nb_of_rx_queue_desc,
+                  const char *device,
+                  u_int32_t queue_id,
+                  char *errbuf)
+{
+    struct xsk_socket_info *xsk_info = (struct xsk_socket_info *)safe_malloc(sizeof(struct xsk_socket_info));
+    struct xsk_socket_config *socket_config = (struct xsk_socket_config *)safe_malloc(sizeof(struct xsk_socket_config));
+
+    socket_config->rx_size = nb_of_rx_queue_desc;
+    socket_config->tx_size = nb_of_tx_queue_desc;
+    socket_config->libbpf_flags = XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
+    socket_config->bind_flags = 0; // XDP_FLAGS_SKB_MODE (1U << 1) or XDP_FLAGS_DRV_MODE (1U << 2)
+    xsk_info = xsk_configure_socket(umem_info, socket_config, queue_id, device);
+
+    if (xsk_info == NULL) {
+        snprintf(errbuf, SENDPACKET_ERRBUF_SIZE, "AF_XDP socket configuration is not successful: %s", strerror(errno));
+        return NULL;
+    }
+    return xsk_info;
+}
+
+/*
+ * gets the hardware address via Linux's PF packet interface
+ */
+static _U_ struct tcpr_ether_addr *
+sendpacket_get_hwaddr_libxdp(sendpacket_t *sp)
+{
+    struct ifreq ifr;
+    int fd;
+
+    assert(sp);
+
+    if (!sp->open) {
+        sendpacket_seterr(sp, "Unable to get hardware address on un-opened sendpacket handle");
+        return NULL;
+    }
+
+    /* create dummy socket for ioctl */
+    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        sendpacket_seterr(sp, "Unable to open dummy socket for get_hwaddr: %s", strerror(errno));
+        return NULL;
+    }
+
+    memset(&ifr, 0, sizeof(ifr));
+    strlcpy(ifr.ifr_name, sp->device, sizeof(ifr.ifr_name));
+
+    if (ioctl(fd, SIOCGIFHWADDR, (int8_t *)&ifr) < 0) {
+        close(fd);
+        sendpacket_seterr(sp, "Error getting hardware address: %s", strerror(errno));
+        return NULL;
+    }
+
+    memcpy(&sp->ether, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
+    close(fd);
+    return (&sp->ether);
+}
+#endif /* HAVE_LIBXDP */

+ 130 - 4
src/common/sendpacket.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -26,7 +26,7 @@
 
 #ifdef __NetBSD__
 #include <net/if_ether.h>
-#else
+#elif ! defined(__HAIKU__)
 #include <netinet/if_ether.h>
 #endif
 
@@ -67,7 +67,9 @@ typedef enum sendpacket_type_e {
     SP_TYPE_TX_RING,
     SP_TYPE_KHIAL,
     SP_TYPE_NETMAP,
-    SP_TYPE_TUNTAP
+    SP_TYPE_TUNTAP,
+    SP_TYPE_LIBPCAP_DUMP,
+    SP_TYPE_LIBXDP
 } sendpacket_type_t;
 
 /* these are the file_operations ioctls */
@@ -80,8 +82,14 @@ typedef enum khial_direction_e {
     KHIAL_DIRECTION_TX,
 } khial_direction_t;
 
+typedef struct pcap_dump_s{
+    pcap_t *pcap;
+    pcap_dumper_t* dump;
+} pcap_dump_t;
+
 union sendpacket_handle {
     pcap_t *pcap;
+    pcap_dump_t dump;
     int fd;
 #ifdef HAVE_LIBDNET
     eth_t *ldnet;
@@ -91,6 +99,71 @@ union sendpacket_handle {
 #define SENDPACKET_ERRBUF_SIZE 1024
 #define MAX_IFNAMELEN 64
 
+#ifdef HAVE_LIBXDP
+#include <errno.h>
+#include <stdlib.h>
+#include <linux/if_xdp.h>
+#include <xdp/xsk.h>
+
+struct xsk_ring_stats {
+    unsigned long rx_npkts;
+    unsigned long tx_npkts;
+    unsigned long rx_dropped_npkts;
+    unsigned long rx_invalid_npkts;
+    unsigned long tx_invalid_npkts;
+    unsigned long rx_full_npkts;
+    unsigned long rx_fill_empty_npkts;
+    unsigned long tx_empty_npkts;
+    unsigned long prev_rx_npkts;
+    unsigned long prev_tx_npkts;
+    unsigned long prev_rx_dropped_npkts;
+    unsigned long prev_rx_invalid_npkts;
+    unsigned long prev_tx_invalid_npkts;
+    unsigned long prev_rx_full_npkts;
+    unsigned long prev_rx_fill_empty_npkts;
+    unsigned long prev_tx_empty_npkts;
+};
+struct xsk_driver_stats {
+    unsigned long intrs;
+    unsigned long prev_intrs;
+};
+struct xsk_app_stats {
+    unsigned long rx_empty_polls;
+    unsigned long fill_fail_polls;
+    unsigned long copy_tx_sendtos;
+    unsigned long tx_wakeup_sendtos;
+    unsigned long opt_polls;
+    unsigned long prev_rx_empty_polls;
+    unsigned long prev_fill_fail_polls;
+    unsigned long prev_copy_tx_sendtos;
+    unsigned long prev_tx_wakeup_sendtos;
+    unsigned long prev_opt_polls;
+};
+struct xsk_umem_info {
+    struct xsk_ring_prod fq;
+    struct xsk_ring_cons cq;
+    struct xsk_umem *umem;
+    void *buffer;
+};
+struct xsk_socket {
+    struct xsk_ring_cons *rx;
+    struct xsk_ring_prod *tx;
+    struct xsk_ctx *ctx;
+    struct xsk_socket_config config;
+    int fd;
+};
+struct xsk_socket_info {
+    struct xsk_ring_cons rx;
+    struct xsk_ring_prod tx;
+    struct xsk_umem_info *umem;
+    struct xsk_socket *xsk;
+    struct xsk_ring_stats ring_stats;
+    struct xsk_app_stats app_stats;
+    struct xsk_driver_stats drv_stats;
+    u_int32_t outstanding_tx;
+};
+#endif /* HAVE_LIBXDP */
+
 struct sendpacket_s {
     tcpr_dir_t cache_dir;
     int open;
@@ -141,11 +214,64 @@ struct sendpacket_s {
     txring_t *tx_ring;
 #endif
 #endif
+#ifdef HAVE_LIBXDP
+    struct xsk_socket_info *xsk_info;
+    struct xsk_umem_info *umem_info;
+    unsigned int batch_size;
+    unsigned int pckt_count;
+    int frame_size;
+    unsigned int tx_idx;
+    int tx_size;
+#endif
     bool abort;
 };
-
 typedef struct sendpacket_s sendpacket_t;
 
+#ifdef HAVE_LIBXDP
+struct xsk_umem_info *
+create_umem_area(int nb_of_frames, int frame_size, int nb_of_completion_queue_descs, int nb_of_fill_queue_descs);
+struct xsk_socket_info *create_xsk_socket(struct xsk_umem_info *umem,
+                                          int nb_of_tx_queue_desc,
+                                          int nb_of_rx_queue_desc,
+                                          const char *device,
+                                          u_int32_t queue_id,
+                                          char *errbuf);
+static inline void
+gen_eth_frame(struct xsk_umem_info *umem, u_int64_t addr, u_char *pkt_data, COUNTER pkt_size)
+{
+    memcpy(xsk_umem__get_data(umem->buffer, addr), pkt_data, pkt_size);
+}
+
+static inline void
+kick_tx(struct xsk_socket_info *xsk)
+{
+    int ret = sendto(xsk_socket__fd(xsk->xsk), NULL, 0, MSG_DONTWAIT, NULL, 0);
+    if (ret >= 0 || errno == ENOBUFS || errno == EAGAIN || errno == EBUSY || errno == ENETDOWN) {
+        return;
+    }
+    printf("%s\n", "Packet sending exited with error!");
+    exit (1);
+}
+
+static inline void
+complete_tx_only(sendpacket_t *sp)
+{
+    u_int32_t completion_idx = 0;
+    if (sp->xsk_info->outstanding_tx == 0) {
+        return;
+    }
+    if (xsk_ring_prod__needs_wakeup(&(sp->xsk_info->tx))) {
+        sp->xsk_info->app_stats.tx_wakeup_sendtos++;
+        kick_tx(sp->xsk_info);
+    }
+    unsigned int rcvd = xsk_ring_cons__peek(&sp->xsk_info->umem->cq, sp->pckt_count, &completion_idx);
+    if (rcvd > 0) {
+        xsk_ring_cons__release(&sp->xsk_info->umem->cq, rcvd);
+        sp->xsk_info->outstanding_tx -= rcvd;
+    }
+}
+#endif /* HAVE_LIBXDP */
+
 int sendpacket(sendpacket_t *, const u_char *, size_t, struct pcap_pkthdr *);
 void sendpacket_close(sendpacket_t *);
 char *sendpacket_geterr(sendpacket_t *);

+ 1 - 1
src/common/services.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 1 - 1
src/common/services.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 2 - 2
src/common/tcpdump.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -75,7 +75,7 @@ tcpdump_print(tcpdump_t *tcpdump, struct pcap_pkthdr *pkthdr, const u_char *data
 
     /* convert header to file-format packet header */
     actual_pkthdr.ts.ts_sec = (uint32_t)pkthdr->ts.tv_sec;
-    actual_pkthdr.ts.ts_usec = (uint32_t)pkthdr->ts.tv_sec;
+    actual_pkthdr.ts.ts_usec = (uint32_t)(pkthdr->ts.tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR);
     actual_pkthdr.caplen = pkthdr->caplen;
     actual_pkthdr.len = pkthdr->len;
 

+ 1 - 1
src/common/tcpdump.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 17 - 4
src/common/timer.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -22,7 +22,7 @@
 #include "config.h"
 #include <stdlib.h>
 
-/* Miscellaneous timeval routines */
+/* Miscellaneous timeval/timespec routines */
 
 /* Divide tvs by div, storing the result in tvs */
 void
@@ -39,7 +39,20 @@ timesdiv_float(struct timespec *tvs, float div)
 }
 
 void
-init_timestamp(timestamp_t *ctx)
+init_timestamp(struct timespec *timestamp)
 {
-    timerclear(ctx);
+    timesclear(timestamp);
+}
+
+int
+get_current_time(struct timespec *ts)
+{
+#if defined CLOCK_MONOTONIC || defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L
+    return clock_gettime(CLOCK_MONOTONIC, ts);
+#else
+    struct timeval tv;
+    int success = gettimeofday(&tv, NULL);
+    TIMEVAL_TO_TIMESPEC(&tv, ts);
+    return success;
+#endif
 }

+ 30 - 2
src/common/timer.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -112,6 +112,33 @@ void timesdiv_float(struct timespec *tvs, float div);
     } while (0)
 #endif
 
+/* add tvp and uvp and store in vvp */
+#ifndef timeradd_timespec
+#define timeradd_timespec(tvp, uvp, vvp)                                                                               \
+    do {                                                                                                               \
+        (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;                                                                 \
+        (vvp)->tv_nsec = (tvp)->tv_nsec + (uvp)->tv_nsec;                                                              \
+        if ((vvp)->tv_nsec >= 1000000000) {                                                                            \
+            (vvp)->tv_sec++;                                                                                           \
+            (vvp)->tv_nsec -= 1000000000;                                                                              \
+        }                                                                                                              \
+    } while (0)
+#endif
+
+/* add tvp and uvp and store in vvp */
+#ifndef timeradd_timeval_timespec
+#define timeradd_timeval_timespec(tvp, uvp, vvp)                                                                       \
+    do {                                                                                                               \
+        (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;                                                                 \
+        (vvp)->tv_nsec = (tvp)->tv_nsec + (uvp)->tv_usec * 1000;                                                       \
+        if ((vvp)->tv_nsec >= 1000000000) {                                                                            \
+            int seconds = (vvp)->tv_nsec % 1000000000;                                                                 \
+            (vvp)->tv_sec += seconds;                                                                                  \
+            (vvp)->tv_nsec -= 1000000000 * seconds;                                                                    \
+        }                                                                                                              \
+    } while (0)
+#endif
+
 /* subtract uvp from tvp and store in vvp */
 #ifndef timersub
 #define timersub(tvp, uvp, vvp)                                                                                        \
@@ -150,4 +177,5 @@ void timesdiv_float(struct timespec *tvs, float div);
 
 typedef struct timeval timestamp_t;
 
-void init_timestamp(timestamp_t *ctx);
+void init_timestamp(struct timespec *timestamp);
+int get_current_time(struct timespec *timestamp);

+ 23 - 11
src/common/utils.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -97,6 +97,17 @@ our_safe_strdup(const char *str, const char *funcname, int line, const char *fil
     return newstr;
 }
 
+pcap_t*
+tcpr_pcap_open(const char *path, char *ebuf)
+{
+#ifdef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
+    return pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf);
+#else
+    return pcap_open_offline(path, ebuf);
+#endif
+}
+
+
 /**
  * calls free and sets to NULL.
  */
@@ -211,7 +222,7 @@ our_safe_pcap_next_ex(pcap_t *pcap,
 void
 packet_stats(const tcpreplay_stats_t *stats)
 {
-    struct timeval diff;
+    struct timespec diff;
     COUNTER diff_us;
     COUNTER bytes_sec = 0;
     u_int32_t bytes_sec_10ths = 0;
@@ -221,8 +232,8 @@ packet_stats(const tcpreplay_stats_t *stats)
     COUNTER pkts_sec = 0;
     u_int32_t pkts_sec_100ths = 0;
 
-    timersub(&stats->end_time, &stats->start_time, &diff);
-    diff_us = TIMEVAL_TO_MICROSEC(&diff);
+    timessub(&stats->end_time, &stats->start_time, &diff);
+    diff_us = TIMESPEC_TO_MICROSEC(&diff);
 
     if (diff_us && stats->pkts_sent && stats->bytes_sent) {
         COUNTER bytes_sec_X10;
@@ -251,18 +262,19 @@ packet_stats(const tcpreplay_stats_t *stats)
         pkts_sec_100ths = pkts_sec_X100 % 100;
     }
 
-    if (diff_us >= 1000 * 1000)
+    if (diff_us >= 1000 * 1000) {
         printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%02zd seconds\n",
                stats->pkts_sent,
                stats->bytes_sent,
                (ssize_t)diff.tv_sec,
-               (ssize_t)(diff.tv_usec / (10 * 1000)));
-    else
+               (ssize_t)(diff.tv_nsec / (10 * 1000000)));
+    } else {
         printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%06zd seconds\n",
                stats->pkts_sent,
                stats->bytes_sent,
                (ssize_t)diff.tv_sec,
-               (ssize_t)diff.tv_usec);
+               (ssize_t)diff.tv_nsec / 1000);
+    }
 
     if (mb_sec >= 1)
         printf("Rated: %llu.%1u Bps, %llu.%02u Mbps, %llu.%02u pps\n",
@@ -295,7 +307,7 @@ packet_stats(const tcpreplay_stats_t *stats)
  * @return: string containing date, or -1 on error
  */
 int
-format_date_time(struct timeval *when, char *buf, size_t len)
+format_date_time(struct timespec *when, char *buf, size_t len)
 {
     struct tm *tm;
     char tmp[64];
@@ -306,8 +318,8 @@ format_date_time(struct timeval *when, char *buf, size_t len)
     if (!tm)
         return -1;
 
-    strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%06u", tm);
-    return snprintf(buf, len, tmp, when->tv_usec);
+    strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%09u", tm);
+    return snprintf(buf, len, tmp, when->tv_nsec);
 }
 
 /**

+ 8 - 7
src/common/utils.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -29,11 +29,11 @@ typedef struct {
     COUNTER bytes_sent;
     COUNTER pkts_sent;
     COUNTER failed;
-    struct timeval start_time;
-    struct timeval time_delta;
-    struct timeval end_time;
-    struct timeval pkt_ts_delta;
-    struct timeval last_print;
+    struct timespec start_time;
+    struct timespec time_delta;
+    struct timespec end_time;
+    struct timespec pkt_ts_delta;
+    struct timespec last_print;
     COUNTER flow_non_flow_packets;
     COUNTER flows;
     COUNTER flows_unique;
@@ -44,9 +44,10 @@ typedef struct {
 
 int read_hexstring(const char *l2string, u_char *hex, int hexlen);
 void packet_stats(const tcpreplay_stats_t *stats);
-int format_date_time(struct timeval *when, char *buf, size_t len);
+int format_date_time(struct timespec *when, char *buf, size_t len);
 uint32_t tcpr_random(uint32_t *seed);
 void restore_stdin(void);
+pcap_t* tcpr_pcap_open(const char *path, char *ebuf);
 
 /* our "safe" implimentations of functions which allocate memory */
 #define safe_malloc(x) our_safe_malloc(x, __FUNCTION__, __LINE__, __FILE__)

+ 1 - 1
src/common/xX.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/common/xX.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 33 - 0
src/config.h.in

@@ -63,6 +63,9 @@
 /* Force using libdnet for sending packets */
 #undef FORCE_INJECT_LIBDNET
 
+/* Force using libxdp for sending packets */
+#undef FORCE_INJECT_LIBXDP
+
 /* Force using libpcap's pcap_inject() for sending packets */
 #undef FORCE_INJECT_PCAP_INJECT
 
@@ -90,6 +93,12 @@
 /* Do we have BPF device support? */
 #undef HAVE_BPF
 
+/* Define to 1 if you have the <bpf/bpf.h> header file. */
+#undef HAVE_BPF_BPF_H
+
+/* Define to 1 if you have the <bpf/libbpf.h> header file. */
+#undef HAVE_BPF_LIBBPF_H
+
 /* Define to 1 if you have the `bzero' function. */
 #undef HAVE_BZERO
 
@@ -124,6 +133,9 @@
 /* Does pcap.h include a header with DLT_LINUX_SLL? */
 #undef HAVE_DLT_LINUX_SLL
 
+/* Does pcap.h include a header with DLT_LINUX_SLL2? */
+#undef HAVE_DLT_LINUX_SLL2
+
 /* Does libpcap have pcap_datalink_val_to_description? */
 #undef HAVE_DLT_VAL_TO_DESC
 
@@ -208,6 +220,12 @@
 /* Define to 1 if you have the `asan' library (-lasan). */
 #undef HAVE_LIBASAN
 
+/* Define to 1 if you have the `bpf' library (-lbpf). */
+#undef HAVE_LIBBPF
+
+/* Define to 1 if you have the `bsd' library (-lbsd). */
+#undef HAVE_LIBBSD
+
 /* Do we have libdnet? */
 #undef HAVE_LIBDNET
 
@@ -238,6 +256,9 @@
 /* Define to 1 if you have the `socket' library (-lsocket). */
 #undef HAVE_LIBSOCKET
 
+/* Do we have LIBXDP AF_XDP socket support? */
+#undef HAVE_LIBXDP
+
 /* Define to 1 if you have the <limits.h> header file. */
 #undef HAVE_LIMITS_H
 
@@ -313,6 +334,9 @@
 /* Does libpcap have pcap_inject? */
 #undef HAVE_PCAP_INJECT
 
+/* Does libpcap have pcap_open_offline_with_tstamp_precision? */
+#undef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
+
 /* Does libpcap have pcap_sendpacket? */
 #undef HAVE_PCAP_SENDPACKET
 
@@ -591,6 +615,9 @@
 /* Define to 1 if `vfork' works. */
 #undef HAVE_WORKING_VFORK
 
+/* Define to 1 if you have the <xdp/libxdp.h> header file. */
+#undef HAVE_XDP_LIBXDP_H
+
 /* Define to 1 if the system has the type `_Bool'. */
 #undef HAVE__BOOL
 
@@ -642,6 +669,12 @@
 /* libpcapnav's version? */
 #undef PCAPNAV_VERSION
 
+/* Multiplier for conversion from PCAP usec to nsec */
+#undef PCAP_TSTAMP_US_TO_NS_MULTIPLIER
+
+/* Divisor for conversion from PCAP usec to usec */
+#undef PCAP_TSTAMP_US_TO_US_DIVISOR
+
 /* define to a working POSIX compliant shell */
 #undef POSIX_SHELL
 

+ 39 - 6
src/defines.h

@@ -48,6 +48,22 @@
 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1
 #endif
 
+#ifdef HAVE_LIBBPF
+#undef HAVE_BPF
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+#define PCAP_DONT_INCLUDE_PCAP_BPF_H 1
+
+struct bpf_program {
+char dummy[0];
+};
+
+#endif
+
+#ifdef HAVE_LIBXDP
+#include <xdp/libxdp.h>
+#endif
+
 #if defined INCLUDE_PCAP_BPF_H_FILE && !defined PCAP_DONT_INCLUDE_PCAP_BPF_H
 #include <@INCLUDE_PCAP_BPF_HEADER@>
 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 /* don't re-include it in pcap.h */
@@ -86,7 +102,7 @@
 #define COUNTER unsigned long
 #define COUNTER_SPEC "%lu"
 #endif
-#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 20)
+#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 23)
 
 #include <common/cidr.h>
 #include <common/list.h>
@@ -101,6 +117,7 @@ typedef struct tcpr_icmpv6_hdr icmpv6_hdr_t;
 typedef struct tcpr_ethernet_hdr eth_hdr_t;
 typedef struct tcpr_802_1q_hdr vlan_hdr_t;
 typedef struct sll_header sll_hdr_t;
+typedef struct sll2_header sll2_hdr_t;
 typedef struct tcpr_arp_hdr arp_hdr_t;
 typedef struct tcpr_dnsv4_hdr dnsv4_hdr_t;
 
@@ -298,10 +315,9 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t
 #define MICROSEC_TO_SEC(x) (x / 1000000)
 #define NANOSEC_TO_SEC(x) ((u_int64_t)x / 1000000000)
 
-#define TIMEVAL_TO_MILLISEC(x) (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000))
-#define TIMEVAL_TO_MICROSEC(x) (((x)->tv_sec * 1000000) + (x)->tv_usec)
-#define TIMEVAL_TO_NANOSEC(x) ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000))
-#define TIMSTAMP_TO_MICROSEC(x) (TIMEVAL_TO_MICROSEC(x))
+#define TIMEVAL_TO_MILLISEC(x)  (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000))
+#define TIMEVAL_TO_MICROSEC(x)  (((x)->tv_sec * 1000000) + (x)->tv_usec)
+#define TIMEVAL_TO_NANOSEC(x)   ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000))
 
 #define MILLISEC_TO_TIMEVAL(x, tv)                                                                                     \
     do {                                                                                                               \
@@ -343,7 +359,24 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t
         (a)->tv_nsec = (b)->tv_nsec;                                                                                   \
     } while (0)
 
-/* 
+/* libpcap that supports it, puts nanosecond values in tv_usec when pcap file is read with nanosec precision,
+ * and so tv_usec is directly copied to tv_nsec.
+ * But older versions do that do not support nanosecond precision need to multiply tv_usec by 1000 to convert
+ * to tv_nsec.
+ */
+#define PCAP_TIMEVAL_TO_TIMESPEC_SET(a, b)                              \
+    do {                                                                \
+        (b)->tv_sec = (a)->tv_sec;                                      \
+        (b)->tv_nsec = (a)->tv_usec * PCAP_TSTAMP_US_TO_NS_MULTIPLIER;  \
+    } while(0)
+
+#define PCAP_TIMEVAL_TO_TIMEVAL_SET(a, b)                               \
+    do {                                                                \
+        (b)->tv_sec = (a)->tv_sec;                                      \
+        (b)->tv_usec = (a)->tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR;     \
+    } while(0)
+
+/*
  * Help suppress some compiler warnings
  * No problem if variable is actually used 
 */

+ 39 - 6
src/defines.h.in

@@ -48,6 +48,22 @@
 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1
 #endif
 
+#ifdef HAVE_LIBBPF
+#undef HAVE_BPF
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+#define PCAP_DONT_INCLUDE_PCAP_BPF_H 1
+
+struct bpf_program {
+char dummy[0];
+};
+
+#endif
+
+#ifdef HAVE_LIBXDP
+#include <xdp/libxdp.h>
+#endif
+
 #if defined INCLUDE_PCAP_BPF_H_FILE && !defined PCAP_DONT_INCLUDE_PCAP_BPF_H
 #include <@INCLUDE_PCAP_BPF_HEADER@>
 #define PCAP_DONT_INCLUDE_PCAP_BPF_H 1 /* don't re-include it in pcap.h */
@@ -86,7 +102,7 @@
 #define COUNTER unsigned long
 #define COUNTER_SPEC "%lu"
 #endif
-#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 20)
+#define COUNTER_OVERFLOW_RISK (((COUNTER)~0) >> 23)
 
 #include <common/cidr.h>
 #include <common/list.h>
@@ -101,6 +117,7 @@ typedef struct tcpr_icmpv6_hdr icmpv6_hdr_t;
 typedef struct tcpr_ethernet_hdr eth_hdr_t;
 typedef struct tcpr_802_1q_hdr vlan_hdr_t;
 typedef struct sll_header sll_hdr_t;
+typedef struct sll2_header sll2_hdr_t;
 typedef struct tcpr_arp_hdr arp_hdr_t;
 typedef struct tcpr_dnsv4_hdr dnsv4_hdr_t;
 
@@ -298,10 +315,9 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t
 #define MICROSEC_TO_SEC(x) (x / 1000000)
 #define NANOSEC_TO_SEC(x) ((u_int64_t)x / 1000000000)
 
-#define TIMEVAL_TO_MILLISEC(x) (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000))
-#define TIMEVAL_TO_MICROSEC(x) (((x)->tv_sec * 1000000) + (x)->tv_usec)
-#define TIMEVAL_TO_NANOSEC(x) ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000))
-#define TIMSTAMP_TO_MICROSEC(x) (TIMEVAL_TO_MICROSEC(x))
+#define TIMEVAL_TO_MILLISEC(x)  (((x)->tv_sec * 1000) + ((x)->tv_usec / 1000))
+#define TIMEVAL_TO_MICROSEC(x)  (((x)->tv_sec * 1000000) + (x)->tv_usec)
+#define TIMEVAL_TO_NANOSEC(x)   ((u_int64_t)((x)->tv_sec * 1000000000) + ((u_int64_t)(x)->tv_usec * 1000))
 
 #define MILLISEC_TO_TIMEVAL(x, tv)                                                                                     \
     do {                                                                                                               \
@@ -343,7 +359,24 @@ typedef u_int8_t uint8_t typedef u_int16_t uint16_t typedef u_int32_t uint32_t
         (a)->tv_nsec = (b)->tv_nsec;                                                                                   \
     } while (0)
 
-/* 
+/* libpcap that supports it, puts nanosecond values in tv_usec when pcap file is read with nanosec precision,
+ * and so tv_usec is directly copied to tv_nsec.
+ * But older versions do that do not support nanosecond precision need to multiply tv_usec by 1000 to convert
+ * to tv_nsec.
+ */
+#define PCAP_TIMEVAL_TO_TIMESPEC_SET(a, b)                              \
+    do {                                                                \
+        (b)->tv_sec = (a)->tv_sec;                                      \
+        (b)->tv_nsec = (a)->tv_usec * PCAP_TSTAMP_US_TO_NS_MULTIPLIER;  \
+    } while(0)
+
+#define PCAP_TIMEVAL_TO_TIMEVAL_SET(a, b)                               \
+    do {                                                                \
+        (b)->tv_sec = (a)->tv_sec;                                      \
+        (b)->tv_usec = (a)->tv_usec / PCAP_TSTAMP_US_TO_US_DIVISOR;     \
+    } while(0)
+
+/*
  * Help suppress some compiler warnings
  * No problem if variable is actually used 
 */

+ 1 - 1
src/fragroute/fragroute.c

@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  * Copyright (c) 2007-2008 Aaron Turner.
- * Copyright (c) 2013-2022 Fred Klassen - AppNeta
+ * Copyright (c) 2013-2024 Fred Klassen - AppNeta
  * $Id$
  */
 

+ 1 - 1
src/fragroute/fragroute.h

@@ -3,7 +3,7 @@
 /*
  *   Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 9 - 9
src/replay.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -117,7 +117,7 @@ replay_file(tcpreplay_t *ctx, int idx)
 
     /* read from pcap file if we haven't cached things yet */
     if (!ctx->options->preload_pcap) {
-        if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
+        if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) {
             tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
             return -1;
         }
@@ -133,7 +133,7 @@ replay_file(tcpreplay_t *ctx, int idx)
 
     } else {
         if (!ctx->options->file_cache[idx].cached) {
-            if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
+            if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) {
                 tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                 return -1;
             }
@@ -145,7 +145,7 @@ replay_file(tcpreplay_t *ctx, int idx)
     if (ctx->options->verbose) {
         /* in cache mode, we may not have opened the file */
         if (pcap == NULL)
-            if ((pcap = pcap_open_offline(path, ebuf)) == NULL) {
+            if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL) {
                 tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                 return -1;
             }
@@ -214,26 +214,26 @@ replay_two_files(tcpreplay_t *ctx, int idx1, int idx2)
 
     /* read from first pcap file if we haven't cached things yet */
     if (!ctx->options->preload_pcap) {
-        if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
+        if ((pcap1 = tcpr_pcap_open(path1, ebuf)) == NULL) {
             tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
             return -1;
         }
         ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
-        if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) {
+        if ((pcap2 = tcpr_pcap_open(path2, ebuf)) == NULL) {
             tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
             return -1;
         }
         ctx->options->file_cache[idx2].dlt = pcap_datalink(pcap2);
     } else {
         if (!ctx->options->file_cache[idx1].cached) {
-            if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
+            if ((pcap1 = tcpr_pcap_open(path1, ebuf)) == NULL) {
                 tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                 return -1;
             }
             ctx->options->file_cache[idx1].dlt = pcap_datalink(pcap1);
         }
         if (!ctx->options->file_cache[idx2].cached) {
-            if ((pcap2 = pcap_open_offline(path2, ebuf)) == NULL) {
+            if ((pcap2 = tcpr_pcap_open(path2, ebuf)) == NULL) {
                 tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                 return -1;
             }
@@ -293,7 +293,7 @@ replay_two_files(tcpreplay_t *ctx, int idx1, int idx2)
     if (ctx->options->verbose) {
         /* in cache mode, we may not have opened the file */
         if (pcap1 == NULL) {
-            if ((pcap1 = pcap_open_offline(path1, ebuf)) == NULL) {
+            if ((pcap1 = tcpr_pcap_open(path1, ebuf)) == NULL) {
                 tcpreplay_seterr(ctx, "Error opening pcap file: %s", ebuf);
                 return -1;
             }

+ 1 - 1
src/replay.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 253 - 118
src/send_packets.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -57,17 +57,20 @@ extern tcpedit_t *tcpedit;
 #include "sleep.h"
 
 static void calc_sleep_time(tcpreplay_t *ctx,
-                            struct timeval *pkt_ts_delta,
-                            struct timeval *time_delta,
+                            struct timespec *pkt_time,
+                            struct timespec *last,
                             COUNTER len,
                             sendpacket_t *sp,
                             COUNTER counter,
-                            timestamp_t *sent_timestamp,
+                            struct timespec *sent_timestamp,
                             COUNTER start_us,
                             COUNTER *skip_length);
-static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp _U_, struct timespec *nap_this_time, struct timeval *now);
-static u_char *
-get_next_packet(tcpreplay_t *ctx, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int file_idx, packet_cache_t **prev_packet);
+static void tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp _U_, struct timespec *nap_this_time, struct timespec *now);
+static u_char *get_next_packet(tcpreplay_opt_t *options,
+                               pcap_t *pcap,
+                               struct pcap_pkthdr *pkthdr,
+                               int file_idx,
+                               packet_cache_t **prev_packet);
 static uint32_t get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter);
 
 #ifdef HAVE_NETMAP
@@ -227,9 +230,11 @@ update_flow_stats(tcpreplay_t *ctx,
                   sendpacket_t *sp,
                   const struct pcap_pkthdr *pkthdr,
                   const u_char *pktdata,
-                  int datalink)
+                  int datalink,
+                  COUNTER packetnum)
 {
-    flow_entry_type_t res = flow_decode(ctx->flow_hash_table, pkthdr, pktdata, datalink, ctx->options->flow_expiry);
+    flow_entry_type_t res =
+            flow_decode(ctx->flow_hash_table, pkthdr, pktdata, datalink, ctx->options->flow_expiry, packetnum);
 
     switch (res) {
     case FLOW_ENTRY_NEW:
@@ -296,14 +301,17 @@ preload_pcap_file(tcpreplay_t *ctx, int idx)
         if (close(1) == -1)
             warnx("unable to close stdin: %s", strerror(errno));
 
-    if ((pcap = pcap_open_offline(path, ebuf)) == NULL)
+    if ((pcap = tcpr_pcap_open(path, ebuf)) == NULL)
         errx(-1, "Error opening pcap file: %s", ebuf);
 
     dlt = pcap_datalink(pcap);
+    COUNTER packetnum = 0;
     /* loop through the pcap.  get_next_packet() builds the cache for us! */
-    while ((pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) {
-        if (options->flow_stats)
-            update_flow_stats(ctx, NULL, &pkthdr, pktdata, dlt);
+    while ((pktdata = get_next_packet(options, pcap, &pkthdr, idx, prev_packet)) != NULL) {
+        if (options->flow_stats) {
+            ++packetnum;
+            update_flow_stats(ctx, NULL, &pkthdr, pktdata, dlt, packetnum);
+        }
     }
 
     /* mark this file as cached */
@@ -332,7 +340,7 @@ increment_iteration(tcpreplay_t *ctx)
 void
 send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
 {
-    struct timeval print_delta, now, last_pkt_ts;
+    struct timespec now, print_delta, last_pkt_ts;
     tcpreplay_opt_t *options = ctx->options;
     tcpreplay_stats_t *stats = &ctx->stats;
     COUNTER packetnum = 0;
@@ -353,10 +361,11 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
     bool top_speed = (options->speed.mode == speed_topspeed ||
                       (options->speed.mode == speed_mbpsrate && options->speed.speed == 0));
     bool now_is_now = true;
+    bool read_next_packet = true; // used for LIBXDP batch packet processing with cached packets
 
-    gettimeofday(&now, NULL);
-    if (!timerisset(&stats->start_time)) {
-        TIMEVAL_SET(&stats->start_time, &now);
+    get_current_time(&now);
+    if (!timesisset(&stats->start_time)) {
+        TIMESPEC_SET(&stats->start_time, &now);
         if (ctx->options->stats >= 0) {
             char buf[64];
             if (format_date_time(&stats->start_time, buf, sizeof(buf)) > 0)
@@ -365,9 +374,9 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
     }
 
     ctx->skip_packets = 0;
-    timerclear(&last_pkt_ts);
+    timesclear(&last_pkt_ts);
     if (options->limit_time > 0)
-        end_us = TIMEVAL_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time);
+        end_us = TIMESPEC_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time);
     else
         end_us = 0;
 
@@ -381,10 +390,24 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
      * Keep sending while we have packets or until
      * we've sent enough packets
      */
-    while (!ctx->abort && (pktdata = get_next_packet(ctx, pcap, &pkthdr, idx, prev_packet)) != NULL) {
+    while (!ctx->abort && read_next_packet &&
+           (pktdata = get_next_packet(options, pcap, &pkthdr, idx, prev_packet)) != NULL) {
+        struct timespec pkthdr_ts;
+        PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr.ts, &pkthdr_ts);
         now_is_now = false;
         packetnum++;
 #if defined TCPREPLAY || defined TCPREPLAY_EDIT
+        /* look for include or exclude LIST match */
+        if (options->list != NULL) {
+            bool rule_set = check_list(options->list, packetnum);
+            if ((rule_set && options->is_exclude) || (!rule_set && !options->is_exclude)) {
+                dbgx(2, "packet " COUNTER_SPEC " not sent due to %s rule",
+                     packetnum,
+                     options->is_exclude ? "exclude" : "include");
+                continue;
+            }
+        }
+
         /* do we use the snaplen (caplen) or the "actual" packet len? */
         pktlen = options->use_pkthdr_len ? (COUNTER)pkthdr.len : (COUNTER)pkthdr.caplen;
 #elif TCPBRIDGE
@@ -422,7 +445,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
 
         /* update flow stats */
         if (options->flow_stats && !preload)
-            update_flow_stats(ctx, options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink);
+            update_flow_stats(ctx, options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink, packetnum);
 
         /*
          * this accelerator improves performance by avoiding expensive
@@ -438,25 +461,25 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
              * time stamping is expensive, but now is the
              * time to do it.
              */
-            dbgx(4, "This packet time: " TIMEVAL_FORMAT, pkthdr.ts.tv_sec, pkthdr.ts.tv_usec);
+            dbgx(4, "This packet time: " TIMESPEC_FORMAT, pkthdr_ts.tv_sec, pkthdr_ts.tv_nsec);
             skip_length = 0;
             ctx->skip_packets = 0;
 
             if (options->speed.mode == speed_multiplier) {
-                if (!timerisset(&last_pkt_ts)) {
-                    TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts);
-                } else if (timercmp(&pkthdr.ts, &last_pkt_ts, >)) {
-                    struct timeval delta;
-
-                    timersub(&pkthdr.ts, &last_pkt_ts, &delta);
-                    timeradd(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta);
-                    TIMEVAL_SET(&last_pkt_ts, &pkthdr.ts);
+                if (!timesisset(&last_pkt_ts)) {
+                    TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts);
+                } else if (timescmp(&pkthdr_ts, &last_pkt_ts, >)) {
+                    struct timespec delta;
+
+                    timessub(&pkthdr_ts, &last_pkt_ts, &delta);
+                    timeradd_timespec(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta);
+                    TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts);
                 }
             }
 
             if (!top_speed) {
                 now_is_now = true;
-                gettimeofday(&now, NULL);
+                get_current_time(&now);
             }
 
             /*
@@ -472,7 +495,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
                             sp,
                             packetnum,
                             &stats->end_time,
-                            TIMEVAL_TO_MICROSEC(&stats->start_time),
+                            TIMESPEC_TO_NANOSEC(&stats->start_time),
                             &skip_length);
 
             /*
@@ -481,14 +504,24 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
              * A number of 3rd party tools generate bad timestamps which go backwards
              * in time.  Hence, don't update the "last" unless pkthdr.ts > last
              */
-            if (timercmp(&stats->time_delta, &stats->pkt_ts_delta, <))
-                TIMEVAL_SET(&stats->time_delta, &stats->pkt_ts_delta);
+            if (timescmp(&stats->time_delta, &stats->pkt_ts_delta, <))
+                TIMESPEC_SET(&stats->time_delta, &stats->pkt_ts_delta);
 
             /*
              * we know how long to sleep between sends, now do it.
              */
-            if (!top_speed)
+            if (!top_speed) {
+#ifndef HAVE_LIBXDP
                 tcpr_sleep(ctx, sp, &ctx->nap, &now);
+#else
+                if (sp->handle_type != SP_TYPE_LIBXDP) {
+                    tcpr_sleep(ctx, sp, &ctx->nap, &now);
+                } else if (sp->batch_size == 1) {
+                    // In case of LIBXDP packet processing waiting only makes sense when batch size is one
+                    tcpr_sleep(ctx, sp, &ctx->nap, &now);
+                }
+#endif
+            }
         }
 
 #ifdef ENABLE_VERBOSE
@@ -497,6 +530,18 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
             tcpdump_print(options->tcpdump, &pkthdr, pktdata);
 #endif
 
+#ifdef HAVE_LIBXDP
+        if (sp->handle_type == SP_TYPE_LIBXDP) {
+            /* Reserve frames for the batc h*/
+            while (xsk_ring_prod__reserve(&(sp->xsk_info->tx), sp->batch_size, &sp->tx_idx) < sp->batch_size) {
+                complete_tx_only(sp);
+            }
+            /* The first packet is already in memory */
+            prepare_first_element_of_batch(ctx, &packetnum, pktdata, pkthdr.len);
+            /* Read more packets and prepare batch */
+            prepare_remaining_elements_of_batch(ctx, &packetnum, &read_next_packet, pcap, &idx, pkthdr, prev_packet);
+        }
+#endif
         dbgx(2, "Sending packet #" COUNTER_SPEC, packetnum);
         /* write packet out on network */
         if (sendpacket(sp, pktdata, pktlen, &pkthdr) < (int)pktlen) {
@@ -507,25 +552,29 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
         /*
          * Mark the time when we sent the last packet
          */
-        TIMEVAL_SET(&stats->end_time, &now);
+        TIMESPEC_SET(&stats->end_time, &now);
 
 #ifdef TIMESTAMP_TRACE
         add_timestamp_trace_entry(pktlen, &stats->end_time, skip_length);
 #endif
 
         stats->pkts_sent++;
+#ifndef HAVE_LIBXDP
         stats->bytes_sent += pktlen;
-
+#else
+        if (sp->handle_type != SP_TYPE_LIBXDP)
+            stats->bytes_sent += pktlen;
+#endif
         /* print stats during the run? */
         if (options->stats > 0) {
-            if (!timerisset(&stats->last_print)) {
-                TIMEVAL_SET(&stats->last_print, &now);
+            if (!timesisset(&stats->last_print)) {
+                TIMESPEC_SET(&stats->last_print, &now);
             } else {
-                timersub(&now, &stats->last_print, &print_delta);
+                timessub(&now, &stats->last_print, &print_delta);
                 if (print_delta.tv_sec >= options->stats) {
-                    TIMEVAL_SET(&stats->end_time, &now);
+                    TIMESPEC_SET(&stats->end_time, &now);
                     packet_stats(stats);
-                    TIMEVAL_SET(&stats->last_print, &now);
+                    TIMESPEC_SET(&stats->last_print, &now);
                 }
             }
         }
@@ -537,7 +586,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
         }
 #endif
         /* stop sending based on the duration limit... */
-        if ((end_us > 0 && (COUNTER)TIMEVAL_TO_MICROSEC(&now) > end_us) ||
+        if ((end_us > 0 && (COUNTER)TIMESPEC_TO_MICROSEC(&now) > end_us) ||
             /* ... or stop sending based on the limit -L? */
             (limit_send > 0 && stats->pkts_sent >= limit_send)) {
             ctx->abort = true;
@@ -549,20 +598,20 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
     if (options->netmap && (ctx->abort || options->loop == 1)) {
         while (ctx->intf1 && !netmap_tx_queues_empty(ctx->intf1)) {
             now_is_now = true;
-            gettimeofday(&now, NULL);
+            get_current_time(&now);
         }
 
         while (ctx->intf2 && !netmap_tx_queues_empty(ctx->intf2)) {
             now_is_now = true;
-            gettimeofday(&now, NULL);
+            get_current_time(&now);
         }
     }
 #endif /* HAVE_NETMAP */
 
     if (!now_is_now)
-        gettimeofday(&now, NULL);
+        get_current_time(&now);
 
-    TIMEVAL_SET(&stats->end_time, &now);
+    TIMESPEC_SET(&stats->end_time, &now);
 
     increment_iteration(ctx);
 }
@@ -574,7 +623,7 @@ send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx)
 void
 send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *pcap2, int cache_file_idx2)
 {
-    struct timeval print_delta, now, last_pkt_ts;
+    struct timespec now, print_delta, last_pkt_ts;
     tcpreplay_opt_t *options = ctx->options;
     tcpreplay_stats_t *stats = &ctx->stats;
     COUNTER packetnum = 0;
@@ -594,9 +643,9 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
                       (options->speed.mode == speed_mbpsrate && options->speed.speed == 0));
     bool now_is_now = true;
 
-    gettimeofday(&now, NULL);
-    if (!timerisset(&stats->start_time)) {
-        TIMEVAL_SET(&stats->start_time, &now);
+    get_current_time(&now);
+    if (!timesisset(&stats->start_time)) {
+        TIMESPEC_SET(&stats->start_time, &now);
         if (ctx->options->stats >= 0) {
             char buf[64];
             if (format_date_time(&stats->start_time, buf, sizeof(buf)) > 0)
@@ -605,9 +654,9 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
     }
 
     ctx->skip_packets = 0;
-    timerclear(&last_pkt_ts);
+    timesclear(&last_pkt_ts);
     if (options->limit_time > 0)
-        end_us = TIMEVAL_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time);
+        end_us = TIMESPEC_TO_MICROSEC(&stats->start_time) + SEC_TO_MICROSEC(options->limit_time);
     else
         end_us = 0;
 
@@ -619,8 +668,8 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
         prev_packet2 = NULL;
     }
 
-    pktdata1 = get_next_packet(ctx, pcap1, &pkthdr1, cache_file_idx1, prev_packet1);
-    pktdata2 = get_next_packet(ctx, pcap2, &pkthdr2, cache_file_idx2, prev_packet2);
+    pktdata1 = get_next_packet(options, pcap1, &pkthdr1, cache_file_idx1, prev_packet1);
+    pktdata2 = get_next_packet(options, pcap2, &pkthdr2, cache_file_idx2, prev_packet2);
 
     /* MAIN LOOP
      * Keep sending while we have packets or until
@@ -629,6 +678,16 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
     while (!ctx->abort && !(pktdata1 == NULL && pktdata2 == NULL)) {
         now_is_now = false;
         packetnum++;
+        /* look for include or exclude LIST match */
+        if (options->list != NULL) {
+            bool rule_set = check_list(options->list, packetnum);
+            if ((rule_set && options->is_exclude) || (!rule_set && !options->is_exclude)) {
+                dbgx(2, "packet " COUNTER_SPEC " not sent due to %s rule",
+                     packetnum,
+                     options->is_exclude ? "exclude" : "include");
+                continue;
+            }
+        }
 
         /* figure out which pcap file we need to process next
          * when get_next_packet() returns null for pktdata, the pkthdr
@@ -684,7 +743,7 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
 
         /* update flow stats */
         if (options->flow_stats && !options->file_cache[cache_file_idx].cached)
-            update_flow_stats(ctx, sp, pkthdr_ptr, pktdata, datalink);
+            update_flow_stats(ctx, sp, pkthdr_ptr, pktdata, datalink, packetnum);
 
         /*
          * this accelerator improves performance by avoiding expensive
@@ -705,22 +764,24 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
             ctx->skip_packets = 0;
 
             if (options->speed.mode == speed_multiplier) {
-                if (!timerisset(&last_pkt_ts)) {
-                    TIMEVAL_SET(&last_pkt_ts, &pkthdr_ptr->ts);
-                } else if (timercmp(&pkthdr_ptr->ts, &last_pkt_ts, >)) {
-                    struct timeval delta;
-
-                    timersub(&pkthdr_ptr->ts, &last_pkt_ts, &delta);
-                    timeradd(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta);
-                    TIMEVAL_SET(&last_pkt_ts, &pkthdr_ptr->ts);
+                struct timespec pkthdr_ts;
+                PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr_ptr->ts, &pkthdr_ts);
+                if (!timesisset(&last_pkt_ts)) {
+                    PCAP_TIMEVAL_TO_TIMESPEC_SET(&pkthdr_ptr->ts, &last_pkt_ts);
+                } else if (timescmp(&pkthdr_ts, &last_pkt_ts, >)) {
+                    struct timespec delta;
+
+                    timessub(&pkthdr_ts, &last_pkt_ts, &delta);
+                    timeradd_timespec(&stats->pkt_ts_delta, &delta, &stats->pkt_ts_delta);
+                    TIMESPEC_SET(&last_pkt_ts, &pkthdr_ts);
                 }
 
-                if (!timerisset(&stats->time_delta))
-                    TIMEVAL_SET(&stats->pkt_ts_delta, &stats->pkt_ts_delta);
+                if (!timesisset(&stats->time_delta))
+                    TIMESPEC_SET(&stats->pkt_ts_delta, &stats->pkt_ts_delta);
             }
 
             if (!top_speed) {
-                gettimeofday(&now, NULL);
+                get_current_time(&now);
                 now_is_now = true;
             }
 
@@ -737,7 +798,7 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
                             sp,
                             packetnum,
                             &stats->end_time,
-                            TIMEVAL_TO_MICROSEC(&stats->start_time),
+                            TIMESPEC_TO_NANOSEC(&stats->start_time),
                             &skip_length);
 
             /*
@@ -746,8 +807,8 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
              * A number of 3rd party tools generate bad timestamps which go backwards
              * in time.  Hence, don't update the "last" unless pkthdr_ptr->ts > last
              */
-            if (timercmp(&stats->time_delta, &stats->pkt_ts_delta, <))
-                TIMEVAL_SET(&stats->time_delta, &stats->pkt_ts_delta);
+            if (timescmp(&stats->time_delta, &stats->pkt_ts_delta, <))
+                TIMESPEC_SET(&stats->time_delta, &stats->pkt_ts_delta);
 
             /*
              * we know how long to sleep between sends, now do it.
@@ -772,21 +833,21 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
         /*
          * Mark the time when we sent the last packet
          */
-        TIMEVAL_SET(&stats->end_time, &now);
+        TIMESPEC_SET(&stats->end_time, &now);
 
         ++stats->pkts_sent;
         stats->bytes_sent += pktlen;
 
         /* print stats during the run? */
         if (options->stats > 0) {
-            if (!timerisset(&stats->last_print)) {
-                TIMEVAL_SET(&stats->last_print, &now);
+            if (!timesisset(&stats->last_print)) {
+                TIMESPEC_SET(&stats->last_print, &now);
             } else {
-                timersub(&now, &stats->last_print, &print_delta);
+                timessub(&now, &stats->last_print, &print_delta);
                 if (print_delta.tv_sec >= options->stats) {
-                    TIMEVAL_SET(&stats->end_time, &now);
+                    TIMESPEC_SET(&stats->end_time, &now);
                     packet_stats(stats);
-                    TIMEVAL_SET(&stats->last_print, &now);
+                    TIMESPEC_SET(&stats->last_print, &now);
                 }
             }
         }
@@ -800,13 +861,13 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
 
         /* get the next packet for this file handle depending on which we last used */
         if (sp == ctx->intf2) {
-            pktdata2 = get_next_packet(ctx, pcap2, &pkthdr2, cache_file_idx2, prev_packet2);
+            pktdata2 = get_next_packet(options, pcap2, &pkthdr2, cache_file_idx2, prev_packet2);
         } else {
-            pktdata1 = get_next_packet(ctx, pcap1, &pkthdr1, cache_file_idx1, prev_packet1);
+            pktdata1 = get_next_packet(options, pcap1, &pkthdr1, cache_file_idx1, prev_packet1);
         }
 
         /* stop sending based on the duration limit... */
-        if ((end_us > 0 && (COUNTER)TIMEVAL_TO_MICROSEC(&now) > end_us) ||
+        if ((end_us > 0 && (COUNTER)TIMESPEC_TO_MICROSEC(&now) > end_us) ||
             /* ... or stop sending based on the limit -L? */
             (limit_send > 0 && stats->pkts_sent >= limit_send)) {
             ctx->abort = true;
@@ -817,21 +878,21 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
     /* when completing test, wait until the last packet is sent */
     if (options->netmap && (ctx->abort || options->loop == 1)) {
         while (ctx->intf1 && !netmap_tx_queues_empty(ctx->intf1)) {
-            gettimeofday(&now, NULL);
+            get_current_time(&now);
             now_is_now = true;
         }
 
         while (ctx->intf2 && !netmap_tx_queues_empty(ctx->intf2)) {
-            gettimeofday(&now, NULL);
+            get_current_time(&now);
             now_is_now = true;
         }
     }
 #endif /* HAVE_NETMAP */
 
     if (!now_is_now)
-        gettimeofday(&now, NULL);
+        get_current_time(&now);
 
-    TIMEVAL_SET(&stats->end_time, &now);
+    TIMESPEC_SET(&stats->end_time, &now);
 
     increment_iteration(ctx);
 }
@@ -845,9 +906,8 @@ send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int cache_file_idx1, pcap_t *
  * will be updated as new entries are added (or retrieved) from the cache list.
  */
 u_char *
-get_next_packet(tcpreplay_t *ctx, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int idx, packet_cache_t **prev_packet)
+get_next_packet(tcpreplay_opt_t *options, pcap_t *pcap, struct pcap_pkthdr *pkthdr, int idx, packet_cache_t **prev_packet)
 {
-    tcpreplay_opt_t *options = ctx->options;
     u_char *pktdata = NULL;
     uint32_t pktlen;
 
@@ -963,18 +1023,18 @@ cache_mode(tcpreplay_t *ctx, char *cachedata, COUNTER packet_num)
  */
 static void
 calc_sleep_time(tcpreplay_t *ctx,
-                struct timeval *pkt_ts_delta,
-                struct timeval *time_delta,
+                struct timespec *pkt_ts_delta,
+                struct timespec *time_delta,
                 COUNTER len,
                 sendpacket_t *sp,
                 COUNTER counter,
-                timestamp_t *sent_timestamp,
-                COUNTER start_us,
+                struct timespec *sent_timestamp,
+                COUNTER start_ns,
                 COUNTER *skip_length)
 {
     tcpreplay_opt_t *options = ctx->options;
-    struct timeval nap_for;
-    COUNTER now_us;
+    struct timespec nap_for;
+    COUNTER now_ns;
 
     timesclear(&ctx->nap);
 
@@ -998,10 +1058,10 @@ calc_sleep_time(tcpreplay_t *ctx,
          * Replay packets a factor of the time they were originally sent.
          * Make sure the packet is not late.
          */
-        if (timercmp(pkt_ts_delta, time_delta, >)) {
+        if (timescmp(pkt_ts_delta, time_delta, >)) {
             /* pkt_time_delta has increased, so handle normally */
-            timersub(pkt_ts_delta, time_delta, &nap_for);
-            TIMEVAL_TO_TIMESPEC(&nap_for, &ctx->nap);
+            timessub(pkt_ts_delta, time_delta, &nap_for);
+            TIMESPEC_SET(&ctx->nap, &nap_for);
             dbgx(3, "original packet delta time: " TIMESPEC_FORMAT, ctx->nap.tv_sec, ctx->nap.tv_nsec);
             timesdiv_float(&ctx->nap, options->speed.multiplier);
             dbgx(3, "original packet delta/div: " TIMESPEC_FORMAT, ctx->nap.tv_sec, ctx->nap.tv_nsec);
@@ -1013,31 +1073,31 @@ calc_sleep_time(tcpreplay_t *ctx,
          * Ignore the time supplied by the capture file and send data at
          * a constant 'rate' (bytes per second).
          */
-        now_us = TIMSTAMP_TO_MICROSEC(sent_timestamp);
-        if (now_us) {
-            COUNTER next_tx_us;
+        now_ns = TIMESPEC_TO_NANOSEC(sent_timestamp);
+        if (now_ns) {
+            COUNTER next_tx_ns;
             COUNTER bps = options->speed.speed;
             COUNTER bits_sent = ((ctx->stats.bytes_sent + len) * 8);
-            COUNTER tx_us = now_us - start_us;
+            COUNTER tx_ns = now_ns - start_ns;
 
             /*
-             * bits * 1000000 divided by bps = microseconds
+             * bits * 1000000000 divided by bps = nanosecond
              *
              * ensure there is no overflow in cases where bits_sent is very high
              */
-            if (bits_sent > COUNTER_OVERFLOW_RISK && bps > 500000)
-                next_tx_us = (bits_sent * 1000) / bps * 1000;
+            if (bits_sent > COUNTER_OVERFLOW_RISK)
+                next_tx_ns = (bits_sent * 1000) / bps * 1000000;
             else
-                next_tx_us = (bits_sent * 1000000) / bps;
+                next_tx_ns = (bits_sent * 1000000000) / bps;
 
-            if (next_tx_us > tx_us) {
-                NANOSEC_TO_TIMESPEC((next_tx_us - tx_us) * 1000, &ctx->nap);
-            } else if (tx_us > next_tx_us) {
-                tx_us = now_us - start_us;
-                *skip_length = ((tx_us - next_tx_us) * bps) / 8000000;
+            if (next_tx_ns > tx_ns) {
+                NANOSEC_TO_TIMESPEC(next_tx_ns - tx_ns, &ctx->nap);
+            } else if (tx_ns > next_tx_ns) {
+                tx_ns = now_ns - start_ns;
+                *skip_length = ((tx_ns - next_tx_ns) * bps) / 8000000000;
             }
 
-            update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_us, tx_us, next_tx_us);
+            update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_ns, tx_ns, next_tx_ns);
         }
 
         dbgx(3, "packet size=" COUNTER_SPEC "\t\tnap=" TIMESPEC_FORMAT, len, ctx->nap.tv_sec, ctx->nap.tv_nsec);
@@ -1048,12 +1108,12 @@ calc_sleep_time(tcpreplay_t *ctx,
          * Ignore the time supplied by the capture file and send data at
          * a constant rate (packets per second).
          */
-        now_us = TIMSTAMP_TO_MICROSEC(sent_timestamp);
-        if (now_us) {
-            COUNTER next_tx_us;
+        now_ns = TIMESPEC_TO_NANOSEC(sent_timestamp);
+        if (now_ns) {
+            COUNTER next_tx_ns;
             COUNTER pph = ctx->options->speed.speed;
             COUNTER pkts_sent = ctx->stats.pkts_sent;
-            COUNTER tx_us = now_us - start_us;
+            COUNTER tx_ns = now_ns - start_ns;
             /*
              * packets * 1000000 divided by pps = microseconds
              * packets per sec (pps) = packets per hour / (60 * 60)
@@ -1062,16 +1122,16 @@ calc_sleep_time(tcpreplay_t *ctx,
              * When active, adjusted calculation may add a bit of jitter.
              */
             if ((pkts_sent < COUNTER_OVERFLOW_RISK))
-                next_tx_us = (pkts_sent * 1000000) * (60 * 60) / pph;
+                next_tx_ns = (pkts_sent * 1000000000) * (60 * 60) / pph;
             else
-                next_tx_us = ((pkts_sent * 1000000) / pph) * (60 * 60);
+                next_tx_ns = ((pkts_sent * 1000000) / pph * 1000) * (60 * 60);
 
-            if (next_tx_us > tx_us)
-                NANOSEC_TO_TIMESPEC((next_tx_us - tx_us) * 1000, &ctx->nap);
+            if (next_tx_ns > tx_ns)
+                NANOSEC_TO_TIMESPEC(next_tx_ns - tx_ns, &ctx->nap);
             else
                 ctx->skip_packets = options->speed.pps_multi;
 
-            update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_us, tx_us, next_tx_us);
+            update_current_timestamp_trace_entry(ctx->stats.bytes_sent + (COUNTER)len, now_ns, tx_ns, next_tx_ns);
         }
 
         dbgx(3,
@@ -1105,7 +1165,7 @@ calc_sleep_time(tcpreplay_t *ctx,
 }
 
 static void
-tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp, struct timespec *nap_this_time, struct timeval *now)
+tcpr_sleep(tcpreplay_t *ctx, sendpacket_t *sp, struct timespec *nap_this_time, struct timespec *now)
 {
     tcpreplay_opt_t *options = ctx->options;
     bool flush =
@@ -1215,3 +1275,78 @@ get_user_count(tcpreplay_t *ctx, sendpacket_t *sp, COUNTER counter)
 
     return (uint32_t)send;
 }
+
+#ifdef HAVE_LIBXDP
+void
+check_packet_fits_in_umem_frame(sendpacket_t *sp, int packet_len)
+{
+    if (packet_len > sp->frame_size) {
+        fprintf(stderr,
+                "ERROR: packet size cannot be larger than the size of an UMEM frame! Packet size: %i  Frame size: %i\n",
+                packet_len,
+                sp->frame_size);
+        free_umem_and_xsk(sp);
+        exit(-1);
+    }
+}
+
+void
+fill_umem_with_data_and_set_xdp_desc(sendpacket_t *sp, int tx_idx, COUNTER umem_index, u_char *pktdata, int len)
+{
+    check_packet_fits_in_umem_frame(sp, len);
+    COUNTER umem_index_mod = (umem_index % sp->batch_size) * sp->frame_size; // packets are sent in batch, after each
+                                                                             // batch umem memory is reusable
+    gen_eth_frame(sp->umem_info, umem_index_mod, pktdata, len);
+    struct xdp_desc *xdp_desc = xsk_ring_prod__tx_desc(&(sp->xsk_info->tx), tx_idx);
+    xdp_desc->addr = (COUNTER)(umem_index_mod);
+    xdp_desc->len = len;
+}
+
+void
+prepare_first_element_of_batch(tcpreplay_t *ctx, COUNTER *packetnum, u_char *pktdata, u_int32_t len)
+{
+    sendpacket_t *sp = ctx->intf1;
+    tcpreplay_stats_t *stats = &ctx->stats;
+    fill_umem_with_data_and_set_xdp_desc(sp, sp->tx_idx, *packetnum - 1, pktdata, len);
+    sp->bytes_sent += len;
+    stats->bytes_sent += len;
+}
+
+void
+prepare_remaining_elements_of_batch(tcpreplay_t *ctx,
+                                    COUNTER *packetnum,
+                                    bool *read_next_packet,
+                                    pcap_t *pcap,
+                                    int *idx,
+                                    struct pcap_pkthdr pkthdr,
+                                    packet_cache_t **prev_packet)
+{
+    sendpacket_t *sp = ctx->intf1;
+    tcpreplay_stats_t *stats = &ctx->stats;
+    int datalink = ctx->options->file_cache[*idx].dlt;
+    bool preload = ctx->options->file_cache[*idx].cached;
+    u_char *pktdata = NULL;
+    unsigned int pckt_count = 1;
+    while (!ctx->abort && (pckt_count < sp->batch_size) &&
+           (pktdata = get_next_packet(ctx->options, pcap, &pkthdr, *idx, prev_packet)) != NULL) {
+        fill_umem_with_data_and_set_xdp_desc(sp, sp->tx_idx + pckt_count, *packetnum, pktdata, pkthdr.len);
+        ++pckt_count;
+        ++*packetnum;
+        stats->bytes_sent += pkthdr.len;
+        sp->bytes_sent += pkthdr.len;
+        stats->pkts_sent++;
+        if (ctx->options->flow_stats && !preload) {
+            update_flow_stats(ctx, ctx->options->cache_packets ? sp : NULL, &pkthdr, pktdata, datalink, *packetnum);
+        }
+    }
+    if (pckt_count < sp->batch_size) {
+        // No more packets to read, it is essential for cached packet processing
+        *read_next_packet = false;
+    }
+    sp->pckt_count = pckt_count;
+    dbgx(2,
+         "Sending packets with LIBXDP in batch, packet numbers from " COUNTER_SPEC " to " COUNTER_SPEC "\n",
+         *packetnum - pckt_count + 1,
+         *packetnum);
+}
+#endif /* HAVE_LIBXDP */

+ 12 - 1
src/send_packets.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -27,3 +27,14 @@ void send_packets(tcpreplay_t *ctx, pcap_t *pcap, int idx);
 void send_dual_packets(tcpreplay_t *ctx, pcap_t *pcap1, int idx1, pcap_t *pcap2, int idx2);
 void *cache_mode(tcpreplay_t *ctx, char *cachedata, COUNTER packet_num);
 void preload_pcap_file(tcpreplay_t *ctx, int idx);
+#ifdef HAVE_LIBXDP
+void prepare_remaining_elements_of_batch(tcpreplay_t *ctx,
+                                         COUNTER *packetnum,
+                                         bool *read_next_packet,
+                                         pcap_t *pcap,
+                                         int *idx,
+                                         struct pcap_pkthdr pkthdr,
+                                         packet_cache_t **prev_packet);
+void prepare_first_element_of_batch(tcpreplay_t *ctx, COUNTER *packetnum, u_char *pktdata, u_int32_t len);
+void fill_umem_with_data_and_set_xdp_desc(sendpacket_t *sp, int tx_idx, COUNTER umem_index, u_char *pktdata, int len);
+#endif

+ 1 - 1
src/signal_handler.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/signal_handler.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 11 - 11
src/sleep.c

@@ -1,6 +1,6 @@
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -49,32 +49,32 @@ ioport_sleep_init(void)
 }
 
 void
-ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap _U_, struct timeval *now _U_, bool flush _U_)
+ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap _U_, struct timespec *now _U_, bool flush _U_)
 {
 #if defined HAVE_IOPORT_SLEEP__
-    struct timeval nap_for;
-    u_int32_t usec;
+    struct timespec nap_for;
+    u_int32_t nsec;
     time_t i;
 
-    TIMESPEC_TO_TIMEVAL(&nap_for, nap);
+    TIMESPEC_SET(&nap_for, nap);
 
     /*
      * process the seconds, we do this in a loop so we don't have to
      * use slower 64bit integers or worry about integer overflows.
      */
     for (i = 0; i < nap_for.tv_sec; i++) {
-        usec = SEC_TO_MICROSEC(nap_for.tv_sec);
+        nsec = nap_for.tv_sec * 1000000000;
         while (usec > 0) {
             usec--;
             outb(ioport_sleep_value, 0x80);
         }
     }
 
-    /* process the usec */
-    usec = nap->tv_nsec / 1000;
-    usec--; /* fudge factor for all the above */
-    while (usec > 0) {
-        usec--;
+    /* process the nsec */
+    nsec = nap->tv_nsec;
+    nsec--; /* fudge factor for all the above */
+    while (nsec > 0) {
+        nsec--;
         outb(ioport_sleep_value, 0x80);
     }
 #else

+ 26 - 17
src/sleep.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <time.h>
 #include <unistd.h>
 #ifdef HAVE_SYS_EVENT
 #include <sys/event.h>
@@ -51,15 +52,22 @@
 #endif /* HAVE_NETMAP */
 
 static inline void
-nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *now, bool flush _U_)
+nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespec *now, bool flush _U_)
 {
+#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L
+    struct timespec sleep_until;
+    timeradd_timespec(now, nap, &sleep_until);
+    clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_until, NULL);
+#else
     nanosleep(nap, NULL);
+#endif
+
 #ifdef HAVE_NETMAP
     if (flush)
         ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
 #endif                                          /* HAVE_NETMAP */
 
-    gettimeofday(now, NULL);
+    get_current_time(now);
 }
 
 /*
@@ -69,36 +77,35 @@ nanosleep_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval
  * Note: make sure "now" has recently been updated.
  */
 static inline void
-gettimeofday_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timeval *now, bool flush _U_)
+gettimeofday_sleep(sendpacket_t *sp, struct timespec *nap, struct timespec *now, bool flush _U_)
 {
-    struct timeval sleep_until, nap_for;
+    struct timespec sleep_until;
 #ifdef HAVE_NETMAP
-    struct timeval last;
+    struct timespec last;
     uint32_t i = 0;
 
-    TIMEVAL_SET(&last, now);
+    TIMESPEC_SET(&last, now);
 #endif /* HAVE_NETMAP */
 
-    TIMESPEC_TO_TIMEVAL(&nap_for, nap);
-    timeradd(now, &nap_for, &sleep_until);
+    timeradd_timespec(now, nap, &sleep_until);
 
     while (!sp->abort) {
 #ifdef HAVE_NETMAP
-        if (flush && timercmp(now, &last, !=)) {
-            TIMEVAL_SET(&last, now);
+        if (flush && timescmp(now, &last, !=)) {
+            TIMESPEC_SET(&last, now);
             if ((++i & 0xf) == 0)
                 /* flush TX buffer every 16 usec */
                 ioctl(sp->handle.fd, NIOCTXSYNC, NULL);
         }
 #endif /* HAVE_NETMAP */
-        if (timercmp(now, &sleep_until, >=))
+        if (timescmp(now, &sleep_until, >=))
             break;
 
 #ifdef HAVE_SCHED_H
         /* yield the CPU so other apps remain responsive */
         sched_yield();
 #endif
-        gettimeofday(now, NULL);
+        get_current_time(now);
     }
 }
 
@@ -110,15 +117,17 @@ gettimeofday_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timeval *n
  * for future reference
  */
 static inline void
-select_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *now, bool flush _U_)
+select_sleep(sendpacket_t *sp _U_, struct timespec *nap, struct timespec *now_ns, bool flush _U_)
 {
     struct timeval timeout;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
 #ifdef HAVE_NETMAP
     if (flush)
         ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
 #endif                                          /* HAVE_NETMAP */
 
-    TIMESPEC_TO_TIMEVAL(&timeout, nap);
+    TIMEVAL_TO_TIMESPEC(&timeout, nap);
 
     if (select(0, NULL, NULL, NULL, &timeout) < 0)
         warnx("select_sleep() returned early due to error: %s", strerror(errno));
@@ -128,7 +137,7 @@ select_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *n
         ioctl(sp->handle.fd, NIOCTXSYNC, NULL); /* flush TX buffer */
 #endif
 
-    gettimeofday(now, NULL);
+    get_current_time(now_ns);
 }
 #endif /* HAVE_SELECT */
 
@@ -143,4 +152,4 @@ select_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *n
 /* before calling port_sleep(), you have to call port_sleep_init() */
 void ioport_sleep_init(void);
 
-void ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timeval *now, bool flush);
+void ioport_sleep(sendpacket_t *sp _U_, const struct timespec *nap, struct timespec *now, bool flush);

+ 16 - 3
src/tcpbridge.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpbridge 1 "11 Jun 2023" "tcpbridge" "User Commands"
+.TH tcpbridge 1 "12 Jul 2024" "tcpbridge" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"
@@ -165,6 +165,15 @@ Causes each IPv4/v6 packet to have their checksums recalculated and
 fixed.  Automatically enabled for packets modified with \fB--seed\fP,
 \fB--pnat\fP, \fB--endpoints\fP or \fB--fixlen\fP.
 .TP
+.NOP \f\*[B-Font]\-\-fixhdrlen\f[]
+Alter IP/TCP header len to match packet length.
+.sp
+By default, tcpreplay will send packets with the original packet length,
+However, you may want the packet length revised to minimum packet size.
+Using this option, tcpreplay will rewrite (fix) the packet length,
+and recalculate checksums when packet length changes.
+Caution: undesired packet changes may occur when this option is specified.
+.TP
 .NOP \f\*[B-Font]\-m\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-mtu\f[]=\f\*[I-Font]number\f[]
 Override default MTU length (1500 bytes).
 This option may appear up to 1 times.
@@ -741,6 +750,10 @@ Print version information.
 Display less usage information and exit.
 .sp
 .TP
+.NOP \f\*[B-Font]\-w\f[], \f\*[B-Font]\-\-suppress\-warnings\f[]
+suppress printing warning messages.
+.sp
+.TP
 .NOP \f\*[B-Font]\-H\f[], \f\*[B-Font]\-\-help\f[]
 Display usage information and exit.
 .TP
@@ -783,13 +796,13 @@ libopts had an internal operational error.  Please report
 it to autogen-users@lists.sourceforge.net.  Thank you.
 .PP
 .SH "AUTHORS"
-Copyright 2013-2022 Fred Klassen \- AppNeta
+Copyright 2013-2024 Fred Klassen \- AppNeta
 Copyright 2000-2012 Aaron Turner
 For support please use the tcpreplay-users@lists.sourceforge.net mailing list.
 The latest version of this software is always available from:
 http://tcpreplay.appneta.com/
 .SH "COPYRIGHT"
-Copyright (C) 2000-2022 Aaron Turner and Fred Klassen all rights reserved.
+Copyright (C) 2000-2024 Aaron Turner and Fred Klassen all rights reserved.
 This program is released under the terms of the GNU General Public License, version 3 or later.
 .SH "BUGS"
 Please send bug reports to: tcpreplay-users@lists.sourceforge.net

+ 5 - 4
src/tcpbridge.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -91,9 +91,9 @@ main(int argc, char *argv[])
     }
 #endif
 
-    if (gettimeofday(&stats.start_time, NULL) < 0) {
+    if (get_current_time(&stats.start_time) < 0) {
         tcpedit_close(&tcpedit);
-        err(-1, "gettimeofday() failed");
+        err(-1, "get_current_time() failed");
     }
 
     /* process packets */
@@ -149,7 +149,8 @@ post_args(_U_ int argc, _U_ char *argv[])
     if (HAVE_OPT(DBUG))
         warn("not configured with --enable-debug.  Debugging disabled.");
 #endif
-
+    if (HAVE_OPT(SUPPRESS_WARNINGS))
+        print_warnings = 0;
 #ifdef ENABLE_VERBOSE
     if (HAVE_OPT(VERBOSE))
         options.verbose = 1;

+ 1 - 1
src/tcpbridge.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

File diff suppressed because it is too large
+ 420 - 360
src/tcpbridge_opts.c


+ 14 - 4
src/tcpbridge_opts.def

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -23,12 +23,12 @@ autogen definitions options;
 
 
 copyright = {
-    date        = "2000-2022";
+    date        = "2000-2024";
     owner       = "Aaron Turner and Fred Klassen";
     eaddr       = "tcpreplay-users@lists.sourceforge.net";
     type        = gpl;
     author      = <<- EOText
-Copyright 2013-2022 Fred Klassen - AppNeta
+Copyright 2013-2024 Fred Klassen - AppNeta
 
 Copyright 2000-2012 Aaron Turner
 
@@ -366,7 +366,7 @@ flag = {
     fprintf(stderr, " (debug)");
 #endif
     fprintf(stderr, "\n");
-    fprintf(stderr, "Copyright 2013-2022 by Fred Klassen <tcpreplay at appneta dot com> - AppNeta\n");
+    fprintf(stderr, "Copyright 2013-2024 by Fred Klassen <tcpreplay at appneta dot com> - AppNeta\n");
     fprintf(stderr, "Copyright 2000-2012 by Aaron Turner <aturner at synfin dot net>\n");
     fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n");
 #ifdef HAVE_LIBDNET
@@ -411,3 +411,13 @@ flag = {
 EOHelp;
     doc         = "";
 };
+
+flag = {
+    name        = suppress-warnings;
+    value       = w;
+    immediate;
+    descrip     = "suppress printing warning messages";
+    settable;
+    doc         = "";
+};
+

+ 83 - 73
src/tcpbridge_opts.h

@@ -19,7 +19,7 @@
  * The tcpbridge program is copyrighted and licensed
  * under the following terms:
  *
- *  Copyright (C) 2000-2022 Aaron Turner and Fred Klassen, all rights reserved.
+ *  Copyright (C) 2000-2024 Aaron Turner and Fred Klassen, all rights reserved.
  *  This is free software. It is licensed for use, modification and
  *  redistribution under the terms of the GNU General Public License,
  *  version 3 or later <http://gnu.org/licenses/gpl.html>
@@ -83,53 +83,55 @@ typedef enum {
     INDEX_OPT_TCP_SEQUENCE              =  7,
     INDEX_OPT_SKIPBROADCAST             =  8,
     INDEX_OPT_FIXCSUM                   =  9,
-    INDEX_OPT_MTU                       = 10,
-    INDEX_OPT_MTU_TRUNC                 = 11,
-    INDEX_OPT_EFCS                      = 12,
-    INDEX_OPT_TTL                       = 13,
-    INDEX_OPT_TOS                       = 14,
-    INDEX_OPT_TCLASS                    = 15,
-    INDEX_OPT_FLOWLABEL                 = 16,
-    INDEX_OPT_FIXLEN                    = 17,
-    INDEX_OPT_FUZZ_SEED                 = 18,
-    INDEX_OPT_FUZZ_FACTOR               = 19,
-    INDEX_OPT_SKIPL2BROADCAST           = 20,
-    INDEX_OPT_DLT                       = 21,
-    INDEX_OPT_ENET_DMAC                 = 22,
-    INDEX_OPT_ENET_SMAC                 = 23,
-    INDEX_OPT_ENET_SUBSMAC              = 24,
-    INDEX_OPT_ENET_MAC_SEED             = 25,
-    INDEX_OPT_ENET_MAC_SEED_KEEP_BYTES  = 26,
-    INDEX_OPT_ENET_VLAN                 = 27,
-    INDEX_OPT_ENET_VLAN_TAG             = 28,
-    INDEX_OPT_ENET_VLAN_CFI             = 29,
-    INDEX_OPT_ENET_VLAN_PRI             = 30,
-    INDEX_OPT_ENET_VLAN_PROTO           = 31,
-    INDEX_OPT_HDLC_CONTROL              = 32,
-    INDEX_OPT_HDLC_ADDRESS              = 33,
-    INDEX_OPT_USER_DLT                  = 34,
-    INDEX_OPT_USER_DLINK                = 35,
-    INDEX_OPT_DBUG                      = 36,
-    INDEX_OPT_INTF1                     = 37,
-    INDEX_OPT_INTF2                     = 38,
-    INDEX_OPT_UNIDIR                    = 39,
-    INDEX_OPT_LISTNICS                  = 40,
-    INDEX_OPT_LIMIT                     = 41,
-    INDEX_OPT_MAC                       = 42,
-    INDEX_OPT_INCLUDE                   = 43,
-    INDEX_OPT_EXCLUDE                   = 44,
-    INDEX_OPT_PID                       = 45,
-    INDEX_OPT_VERBOSE                   = 46,
-    INDEX_OPT_DECODE                    = 47,
-    INDEX_OPT_VERSION                   = 48,
-    INDEX_OPT_LESS_HELP                 = 49,
-    INDEX_OPT_HELP                      = 50,
-    INDEX_OPT_MORE_HELP                 = 51,
-    INDEX_OPT_SAVE_OPTS                 = 52,
-    INDEX_OPT_LOAD_OPTS                 = 53
+    INDEX_OPT_FIXHDRLEN                 = 10,
+    INDEX_OPT_MTU                       = 11,
+    INDEX_OPT_MTU_TRUNC                 = 12,
+    INDEX_OPT_EFCS                      = 13,
+    INDEX_OPT_TTL                       = 14,
+    INDEX_OPT_TOS                       = 15,
+    INDEX_OPT_TCLASS                    = 16,
+    INDEX_OPT_FLOWLABEL                 = 17,
+    INDEX_OPT_FIXLEN                    = 18,
+    INDEX_OPT_FUZZ_SEED                 = 19,
+    INDEX_OPT_FUZZ_FACTOR               = 20,
+    INDEX_OPT_SKIPL2BROADCAST           = 21,
+    INDEX_OPT_DLT                       = 22,
+    INDEX_OPT_ENET_DMAC                 = 23,
+    INDEX_OPT_ENET_SMAC                 = 24,
+    INDEX_OPT_ENET_SUBSMAC              = 25,
+    INDEX_OPT_ENET_MAC_SEED             = 26,
+    INDEX_OPT_ENET_MAC_SEED_KEEP_BYTES  = 27,
+    INDEX_OPT_ENET_VLAN                 = 28,
+    INDEX_OPT_ENET_VLAN_TAG             = 29,
+    INDEX_OPT_ENET_VLAN_CFI             = 30,
+    INDEX_OPT_ENET_VLAN_PRI             = 31,
+    INDEX_OPT_ENET_VLAN_PROTO           = 32,
+    INDEX_OPT_HDLC_CONTROL              = 33,
+    INDEX_OPT_HDLC_ADDRESS              = 34,
+    INDEX_OPT_USER_DLT                  = 35,
+    INDEX_OPT_USER_DLINK                = 36,
+    INDEX_OPT_DBUG                      = 37,
+    INDEX_OPT_INTF1                     = 38,
+    INDEX_OPT_INTF2                     = 39,
+    INDEX_OPT_UNIDIR                    = 40,
+    INDEX_OPT_LISTNICS                  = 41,
+    INDEX_OPT_LIMIT                     = 42,
+    INDEX_OPT_MAC                       = 43,
+    INDEX_OPT_INCLUDE                   = 44,
+    INDEX_OPT_EXCLUDE                   = 45,
+    INDEX_OPT_PID                       = 46,
+    INDEX_OPT_VERBOSE                   = 47,
+    INDEX_OPT_DECODE                    = 48,
+    INDEX_OPT_VERSION                   = 49,
+    INDEX_OPT_LESS_HELP                 = 50,
+    INDEX_OPT_SUPPRESS_WARNINGS         = 51,
+    INDEX_OPT_HELP                      = 52,
+    INDEX_OPT_MORE_HELP                 = 53,
+    INDEX_OPT_SAVE_OPTS                 = 54,
+    INDEX_OPT_LOAD_OPTS                 = 55
 } teOptIndex;
 /** count of all options for tcpbridge */
-#define OPTION_CT    54
+#define OPTION_CT    56
 
 /**
  *  Interface defines for all options.  Replace "n" with the UPPER_CASED
@@ -194,60 +196,61 @@ typedef enum {
 #define OPT_VALUE_TCP_SEQUENCE   (DESC(TCP_SEQUENCE).optArg.argInt)
 #define VALUE_OPT_SKIPBROADCAST  'b'
 #define VALUE_OPT_FIXCSUM        'C'
+#define VALUE_OPT_FIXHDRLEN      0x1002
 #define VALUE_OPT_MTU            'm'
 
 #define OPT_VALUE_MTU            (DESC(MTU).optArg.argInt)
-#define VALUE_OPT_MTU_TRUNC      0x1002
+#define VALUE_OPT_MTU_TRUNC      0x1003
 #define VALUE_OPT_EFCS           'E'
-#define VALUE_OPT_TTL            0x1003
-#define VALUE_OPT_TOS            0x1004
+#define VALUE_OPT_TTL            0x1004
+#define VALUE_OPT_TOS            0x1005
 
 #define OPT_VALUE_TOS            (DESC(TOS).optArg.argInt)
-#define VALUE_OPT_TCLASS         0x1005
+#define VALUE_OPT_TCLASS         0x1006
 
 #define OPT_VALUE_TCLASS         (DESC(TCLASS).optArg.argInt)
-#define VALUE_OPT_FLOWLABEL      0x1006
+#define VALUE_OPT_FLOWLABEL      0x1007
 
 #define OPT_VALUE_FLOWLABEL      (DESC(FLOWLABEL).optArg.argInt)
 #define VALUE_OPT_FIXLEN         'F'
-#define VALUE_OPT_FUZZ_SEED      0x1007
+#define VALUE_OPT_FUZZ_SEED      0x1008
 
 #define OPT_VALUE_FUZZ_SEED      (DESC(FUZZ_SEED).optArg.argInt)
-#define VALUE_OPT_FUZZ_FACTOR    0x1008
+#define VALUE_OPT_FUZZ_FACTOR    0x1009
 
 #define OPT_VALUE_FUZZ_FACTOR    (DESC(FUZZ_FACTOR).optArg.argInt)
-#define VALUE_OPT_SKIPL2BROADCAST 0x1009
-#define VALUE_OPT_DLT            0x100A
-#define VALUE_OPT_ENET_DMAC      0x100B
-#define VALUE_OPT_ENET_SMAC      0x100C
-#define VALUE_OPT_ENET_SUBSMAC   0x100D
-#define VALUE_OPT_ENET_MAC_SEED  0x100E
+#define VALUE_OPT_SKIPL2BROADCAST 0x100A
+#define VALUE_OPT_DLT            0x100B
+#define VALUE_OPT_ENET_DMAC      0x100C
+#define VALUE_OPT_ENET_SMAC      0x100D
+#define VALUE_OPT_ENET_SUBSMAC   0x100E
+#define VALUE_OPT_ENET_MAC_SEED  0x100F
 
 #define OPT_VALUE_ENET_MAC_SEED  (DESC(ENET_MAC_SEED).optArg.argInt)
-#define VALUE_OPT_ENET_MAC_SEED_KEEP_BYTES 0x100F
+#define VALUE_OPT_ENET_MAC_SEED_KEEP_BYTES 0x1010
 
 #define OPT_VALUE_ENET_MAC_SEED_KEEP_BYTES (DESC(ENET_MAC_SEED_KEEP_BYTES).optArg.argInt)
-#define VALUE_OPT_ENET_VLAN      0x1010
-#define VALUE_OPT_ENET_VLAN_TAG  0x1011
+#define VALUE_OPT_ENET_VLAN      0x1011
+#define VALUE_OPT_ENET_VLAN_TAG  0x1012
 
 #define OPT_VALUE_ENET_VLAN_TAG  (DESC(ENET_VLAN_TAG).optArg.argInt)
-#define VALUE_OPT_ENET_VLAN_CFI  0x1012
+#define VALUE_OPT_ENET_VLAN_CFI  0x1013
 
 #define OPT_VALUE_ENET_VLAN_CFI  (DESC(ENET_VLAN_CFI).optArg.argInt)
-#define VALUE_OPT_ENET_VLAN_PRI  0x1013
+#define VALUE_OPT_ENET_VLAN_PRI  0x1014
 
 #define OPT_VALUE_ENET_VLAN_PRI  (DESC(ENET_VLAN_PRI).optArg.argInt)
-#define VALUE_OPT_ENET_VLAN_PROTO 0x1014
-#define VALUE_OPT_HDLC_CONTROL   0x1015
+#define VALUE_OPT_ENET_VLAN_PROTO 0x1015
+#define VALUE_OPT_HDLC_CONTROL   0x1016
 
 #define OPT_VALUE_HDLC_CONTROL   (DESC(HDLC_CONTROL).optArg.argInt)
-#define VALUE_OPT_HDLC_ADDRESS   0x1016
+#define VALUE_OPT_HDLC_ADDRESS   0x1017
 
 #define OPT_VALUE_HDLC_ADDRESS   (DESC(HDLC_ADDRESS).optArg.argInt)
-#define VALUE_OPT_USER_DLT       0x1017
+#define VALUE_OPT_USER_DLT       0x1018
 
 #define OPT_VALUE_USER_DLT       (DESC(USER_DLT).optArg.argInt)
-#define VALUE_OPT_USER_DLINK     0x1018
+#define VALUE_OPT_USER_DLINK     0x1019
 #define VALUE_OPT_DBUG           'd'
 #ifdef DEBUG
 #define OPT_VALUE_DBUG           (DESC(DBUG).optArg.argInt)
@@ -255,7 +258,7 @@ typedef enum {
 #define VALUE_OPT_INTF1          'i'
 #define VALUE_OPT_INTF2          'I'
 #define VALUE_OPT_UNIDIR         'u'
-#define VALUE_OPT_LISTNICS       0x1019
+#define VALUE_OPT_LISTNICS       0x101A
 #define VALUE_OPT_LIMIT          'L'
 
 #define OPT_VALUE_LIMIT          (DESC(LIMIT).optArg.argInt)
@@ -266,7 +269,7 @@ typedef enum {
 #define VALUE_OPT_VERBOSE        'v'
 #ifdef ENABLE_VERBOSE
 #define SET_OPT_VERBOSE   STMTS( \
-        DESC(VERBOSE).optActualIndex = 46; \
+        DESC(VERBOSE).optActualIndex = 47; \
         DESC(VERBOSE).optActualValue = VALUE_OPT_VERBOSE; \
         DESC(VERBOSE).fOptState &= OPTST_PERSISTENT_MASK; \
         DESC(VERBOSE).fOptState |= OPTST_SET )
@@ -274,14 +277,21 @@ typedef enum {
 #define VALUE_OPT_DECODE         'A'
 #define VALUE_OPT_VERSION        'V'
 #define VALUE_OPT_LESS_HELP      'h'
+#define VALUE_OPT_SUPPRESS_WARNINGS 'w'
+
+#define SET_OPT_SUPPRESS_WARNINGS   STMTS( \
+        DESC(SUPPRESS_WARNINGS).optActualIndex = 51; \
+        DESC(SUPPRESS_WARNINGS).optActualValue = VALUE_OPT_SUPPRESS_WARNINGS; \
+        DESC(SUPPRESS_WARNINGS).fOptState &= OPTST_PERSISTENT_MASK; \
+        DESC(SUPPRESS_WARNINGS).fOptState |= OPTST_SET )
 /** option flag (value) for help-value option */
 #define VALUE_OPT_HELP          'H'
 /** option flag (value) for more-help-value option */
 #define VALUE_OPT_MORE_HELP     '!'
 /** option flag (value) for save-opts-value option */
-#define VALUE_OPT_SAVE_OPTS     0x101A
+#define VALUE_OPT_SAVE_OPTS     0x101B
 /** option flag (value) for load-opts-value option */
-#define VALUE_OPT_LOAD_OPTS     0x101B
+#define VALUE_OPT_LOAD_OPTS     0x101C
 #define SET_OPT_SAVE_OPTS(a)   STMTS( \
         DESC(SAVE_OPTS).fOptState &= OPTST_PERSISTENT_MASK; \
         DESC(SAVE_OPTS).fOptState |= OPTST_SET; \

+ 1 - 1
src/tcpcapinfo.1

@@ -10,7 +10,7 @@
 .ds B-Font B
 .ds I-Font I
 .ds R-Font R
-.TH tcpcapinfo 1 "11 Jun 2023" "Tcpreplay Suite" "User Commands"
+.TH tcpcapinfo 1 "12 Jul 2024" "Tcpreplay Suite" "User Commands"
 .\"
 .\" DO NOT EDIT THIS FILE (in-mem file)
 .\"

+ 1 - 1
src/tcpcapinfo.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2012 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpcapinfo_opts.c

@@ -349,7 +349,7 @@ doOptVersion(tOptions* pOptions, tOptDesc* pOptDesc)
     fprintf(stderr, " (debug)");
 #endif
     fprintf(stderr, "\n");
-    fprintf(stderr, "Copyright 2013-2022 by Fred Klassen <tcpreplay at appneta dot com> - AppNeta\n");
+    fprintf(stderr, "Copyright 2013-2024 by Fred Klassen <tcpreplay at appneta dot com> - AppNeta\n");
     fprintf(stderr, "Copyright 2000-2010 by Aaron Turner <aturner at synfin dot net>\n");
     fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n");
     exit(0);

+ 2 - 2
src/tcpcapinfo_opts.def

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 
@@ -102,7 +102,7 @@ flag = {
     fprintf(stderr, " (debug)");
 #endif
     fprintf(stderr, "\n");
-    fprintf(stderr, "Copyright 2013-2022 by Fred Klassen <tcpreplay at appneta dot com> - AppNeta\n");
+    fprintf(stderr, "Copyright 2013-2024 by Fred Klassen <tcpreplay at appneta dot com> - AppNeta\n");
     fprintf(stderr, "Copyright 2000-2010 by Aaron Turner <aturner at synfin dot net>\n");
     fprintf(stderr, "The entire Tcpreplay Suite is licensed under the GPLv3\n");
     exit(0);

File diff suppressed because it is too large
+ 45 - 3
src/tcpedit/Makefile.in


+ 1 - 1
src/tcpedit/checksum.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/checksum.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 10 - 7
src/tcpedit/dlt.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -21,6 +21,7 @@
 #include "dlt.h"
 #include "config.h"
 #include "tcpedit.h"
+#include <lib/sll.h>
 #include <assert.h>
 
 /**
@@ -49,13 +50,13 @@ dlt2layer2len(tcpedit_t *tcpedit, int dlt)
     case DLT_EN10MB:
         len = 12;
         break;
-        /*
-    case DLT_VLAN:
-        len = 14;
-        break;
-        */
+
     case DLT_LINUX_SLL:
-        len = 16;
+        len = SLL_HDR_LEN;
+        break;
+
+    case DLT_LINUX_SLL2:
+        len = SLL2_HDR_LEN;
         break;
 
     case DLT_PPP_SERIAL:
@@ -103,6 +104,7 @@ dltrequires(tcpedit_t *tcpedit, int dlt)
         break;
 
     case DLT_LINUX_SLL:
+    case DLT_LINUX_SLL2:
         /* we have proto & SRC address */
         req = TCPEDIT_DLT_DST;
         break;
@@ -136,6 +138,7 @@ dlt2mtu(tcpedit_t *tcpedit, int dlt)
         break;
 
     case DLT_LINUX_SLL:
+    case DLT_LINUX_SLL2:
         mtu = 16436;
         break;
 

+ 1 - 1
src/tcpedit/dlt.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 8 - 7
src/tcpedit/edit_packet.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -78,12 +78,13 @@ fix_ipv4_checksums(tcpedit_t *tcpedit, struct pcap_pkthdr *pkthdr, ipv4_hdr_t *i
     /* calc the L4 checksum if we have the whole packet && not a frag or first frag */
     if (pkthdr->caplen == pkthdr->len && (htons(ip_hdr->ip_off) & (IP_MF | IP_OFFMASK)) == 0) {
         if (ip_len != (int)(pkthdr->caplen - l2len)) {
-            tcpedit_seterr(tcpedit,
-                           "caplen minus L2 length %u does IPv4 header length %u: pkt=" COUNTER_SPEC,
-                           pkthdr->caplen - l2len,
-                           ip_len,
-                           tcpedit->runtime.packetnum);
-            return TCPEDIT_ERROR;
+            tcpedit_setwarn(tcpedit,
+                            "skipping packet " COUNTER_SPEC " because caplen %u minus L2 length %zu does not equal IPv4 header length %u. Consider option '--fixhdrlen'.",
+                            tcpedit->runtime.packetnum,
+                            pkthdr->caplen,
+                            l2len,
+                            ip_len);
+            return TCPEDIT_WARN;
         }
         ret1 = do_checksum(tcpedit,
                            (u_char *)ip_hdr,

+ 1 - 1
src/tcpedit/edit_packet.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 5 - 1
src/tcpedit/parse_args.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -95,6 +95,10 @@ tcpedit_post_args(tcpedit_t *tcpedit)
     if (HAVE_OPT(FIXCSUM))
         tcpedit->fixcsum = true;
 
+    /* --fixhdrlen */
+    if (HAVE_OPT(FIXHDRLEN))
+        tcpedit->fixhdrlen = true;
+
     /* --efcs */
     if (HAVE_OPT(EFCS))
         tcpedit->efcs = true;

+ 1 - 1
src/tcpedit/parse_args.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 0
src/tcpedit/plugins/Makefile.am

@@ -42,6 +42,7 @@ include %reldir%/dlt_raw/Makefile.am
 include %reldir%/dlt_null/Makefile.am
 include %reldir%/dlt_loop/Makefile.am
 include %reldir%/dlt_linuxsll/Makefile.am
+include %reldir%/dlt_linuxsll2/Makefile.am
 include %reldir%/dlt_ieee80211/Makefile.am
 include %reldir%/dlt_radiotap/Makefile.am
 include %reldir%/dlt_jnpr_ether/Makefile.am

+ 12 - 8
src/tcpedit/plugins/dlt_en10mb/en10mb.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as
@@ -184,7 +184,7 @@ dlt_en10mb_parse_subsmac(tcpeditdlt_t *ctx, en10mb_config_t *config, const char
 {
     size_t input_len = strlen(input);
     size_t possible_entries_number = (input_len / (SUBSMAC_ENTRY_LEN + 1)) + 1;
-    int entry;
+    size_t entry;
 
     en10mb_sub_entry_t *entries = safe_malloc(possible_entries_number * sizeof(en10mb_sub_entry_t));
 
@@ -519,12 +519,12 @@ dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir)
     }
 
     /* newl2len for some other DLT -> ethernet */
-    else if (config->vlan == TCPEDIT_VLAN_ADD) {
-        /* if add a vlan then 18, */
-        newl2len = TCPR_802_1Q_H;
+    else {
+        newl2len = config->vlan == TCPEDIT_VLAN_ADD ? TCPR_802_1Q_H : TCPR_802_3_H;
+        oldl2len = ctx->l2len;
     }
 
-    if (pktlen < newl2len || pktlen + newl2len - ctx->l2len > MAXPACKET) {
+    if ((uint32_t)pktlen < newl2len || pktlen + newl2len - ctx->l2len > MAXPACKET) {
         tcpedit_seterr(ctx->tcpedit,
                        "Unable to process packet #" COUNTER_SPEC " since its new length is %d bytes.",
                        ctx->tcpedit->runtime.packetnum,
@@ -555,7 +555,6 @@ dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir)
 
     /* update the total packet length */
     pktlen += (int)(newl2len - oldl2len);
-    ctx->l2len += (int)(newl2len - oldl2len);
 
     /* set the src & dst address as the first 12 bytes */
     eth = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset);
@@ -665,6 +664,11 @@ dlt_en10mb_encode(tcpeditdlt_t *ctx, u_char *packet, int pktlen, tcpr_dir_t dir)
         }
     }
 
+    if (newl2len == TCPR_802_3_H) {
+        /* all we need for 802.3 is the proto */
+        eth->ether_type = ctx->proto;
+    }
+
     if (config->vlan == TCPEDIT_VLAN_ADD || (config->vlan == TCPEDIT_VLAN_OFF && extra->vlan)) {
         vlan_hdr = (struct tcpr_802_1q_hdr *)(packet + extra->vlan_offset);
         if (config->vlan == TCPEDIT_VLAN_ADD) {
@@ -812,7 +816,7 @@ dlt_en10mb_merge_layer3(tcpeditdlt_t *ctx, u_char *packet, int pktlen, u_char *i
     if (l2len == -1 || pktlen < l2len)
         return NULL;
 
-    assert(ctx->decoded_extra_size == sizeof(*extra));
+    assert(ctx->decoded_extra_size >= sizeof(*extra));
     extra = (en10mb_extra_t *)ctx->decoded_extra;
     eth = (struct tcpr_ethernet_hdr *)(packet + ctx->l2offset);
     assert(eth);

+ 1 - 1
src/tcpedit/plugins/dlt_en10mb/en10mb.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it 
  *   and/or modify it under the terms of the GNU General Public License as 

+ 1 - 1
src/tcpedit/plugins/dlt_en10mb/en10mb_api.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_en10mb/en10mb_api.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_en10mb/en10mb_types.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_hdlc/hdlc.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_hdlc/hdlc.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_hdlc/hdlc_api.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_hdlc/hdlc_api.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_hdlc/hdlc_types.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_ieee80211/ieee80211.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_ieee80211/ieee80211.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.c

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_ieee80211/ieee80211_hdr.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 1 - 1
src/tcpedit/plugins/dlt_ieee80211/ieee80211_types.h

@@ -2,7 +2,7 @@
 
 /*
  *   Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
- *   Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ *   Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  *
  *   The Tcpreplay Suite of tools is free software: you can redistribute it
  *   and/or modify it under the terms of the GNU General Public License as

+ 11 - 5
src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.c

@@ -2,7 +2,7 @@
 
 /*
  * Copyright (c) 2006-2007 Aaron Turner.
- * Copyright (c) 2013-2022 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
+ * Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,9 +64,7 @@ dlt_jnpr_ether_register(tcpeditdlt_t *ctx)
     plugin = tcpedit_dlt_newplugin();
 
     plugin->provides += PLUGIN_MASK_PROTO + PLUGIN_MASK_SRCADDR + PLUGIN_MASK_DSTADDR;
-    plugin->
-        requires
-    = 0;
+    plugin->requires = 0;
 
     /* what is our DLT value? */
     plugin->dlt = dlt_value;
@@ -164,8 +162,9 @@ dlt_jnpr_ether_cleanup(tcpeditdlt_t *ctx)
         jnpr_ether_config_t *config;
 
         config = (jnpr_ether_config_t *)ctx->encoder->config;
-        if (config->subctx != NULL)
+        if (config != NULL && config->subctx != NULL) {
             tcpedit_dlt_cleanup(config->subctx);
+        }
         safe_free(plugin->config);
         plugin->config = NULL;
         plugin->config_size = 0;
@@ -303,6 +302,13 @@ dlt_jnpr_ether_proto(tcpeditdlt_t *ctx, const u_char *packet, int pktlen)
     memcpy(&jnpr_hdr_len, &packet[JUNIPER_ETHER_EXTLEN_OFFSET], 2);
 
     jnpr_hdr_len = ntohs(jnpr_hdr_len) + JUNIPER_ETHER_HEADER_LEN;
+    if (jnpr_hdr_len > pktlen) {
+        tcpedit_seterr(ctx->tcpedit,
+                       "Juniper header length %d invalid: it is greater than packet length %d",
+                       jnpr_hdr_len, pktlen);
+        return TCPEDIT_ERROR;
+    }
+
     ethernet = packet + jnpr_hdr_len;
 
     /* let the en10mb plugin do the rest of the work */

+ 0 - 0
src/tcpedit/plugins/dlt_jnpr_ether/jnpr_ether.h


Some files were not shown because too many files changed in this diff