diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/AUTHORS ns-3.42/AUTHORS
--- ns-3.41/AUTHORS	2024-02-09 14:44:07.717788700 -0800
+++ ns-3.42/AUTHORS	2024-05-29 15:29:46.824072800 -0700
@@ -1,3 +1,4 @@
+Rami Abdallah <abdallah.rami@gmail.com>
 Eduardo Abinader (eduardo.abinader@gmail.com)
 John Abraham (john.abraham.in@gmail.com)
 Danilo Abrignani (dabrignani@gmail.com)
@@ -43,6 +44,7 @@
 Dan Broyles (muxman@sbcglobal.net)
 Jonathan Brugge (j.d.brugge@student.utwente.nl)
 Junling Bu (linlinjavaer@gmail.com)
+Alessio Bugetti (alessiobugetti98@gmail.com)
 Elena Buchatskaia (borovkovaes@iitp.ru)
 Alessio Bugetti (alessiobugetti98@gmail.com)
 Nuno Cardoso (nunopcardoso@gmail.com)
@@ -56,6 +58,7 @@
 Shobhit Chaurasia (000shobhitchaurasia@gmail.com)
 Luciano Jerez Chaves (ljerezchaves@gmail.com)
 Eugene Chemeritskiy (echemeritskiy@arccn.ru)
+Rui Chen (rui@chenrui.dev)
 Yufei Cheng (yfcheng@ittc.ku.edu)
 Aditya Chirania (adityachirania97@gmail.com)
 Zhao Wen Chow (shu@mos.ics.keio.ac.jp)
@@ -136,6 +139,7 @@
 Sourabh Jain (jainsourabh679@gmail.com)
 Vivek Jain (jain.vivek.anand@gmail.com)
 Sam Jansen (sam.jansen@gmail.com)
+Jacob Janzen (jacob.a.s.janzen@gmail.com)
 Chandrakant Jena (chandrakant.barcelona@gmail.com)
 Liu Jian (liujatp@gmail.com)
 Sascha Alexander Jopen (jopen@informatik.uni-bonn.de)
@@ -151,6 +155,7 @@
 Morteza Kheirkhah (m.kheirkhah@sussex.ac.uk)
 Jörg Christian Kirchhof (christian.kirchhof@rwth-aachen.de)
 Ohad Klausner
+Wojtek Kosior (koszko@koszko.org)
 Katarina Koutlia (katerina.koutlia@cttc.es)
 Shravya Ks (shravya.ks0@gmail.com)
 Flavio Kubota (flaviokubota@gmail.com)
@@ -193,6 +198,7 @@
 Jonathan McCrohan (jmccroha@tcd.ie)
 Andrew McGregor (andrewmcgr@gmail.com)
 Miralem Mehic (miralemmehic@gmail.com)
+Zili Meng (zilim@ieee.org)
 Levente Mészáros (levy@omnetpp.org)
 Vedran Miletić (rivanvx@gmail.com)
 Saswat Mishra (clicksaswat@gmail.com)
@@ -270,11 +276,13 @@
 Ali Rostami (a.rostami@rutgers.edu)
 Bill Roome (wdr@bell-labs.com)
 David Rua (david.rua@gmail.com)
+Chan Ruihua (chenrh20@mails.tsinghua.edu.cn)
 Andrea Sacco (andrea.sacco85@gmail.com)
 Richard Sailer (richard_sailer@systemli.org)
 Lynne Salameh (l.salameh@cs.ucl.ac.uk)
 Providence Salumu Munga (Providence.Salumu@gmail.com, Providence.Salumu_Munga@it-sudparis.eu)
 Francisco Javier Sánchez-Roselly (fnavarro@ujaen.es)
+Mattia Sandri (sandrimatt@dei.unipd.it)
 Charitha Sangaraju (charitha29193@gmail.com)
 Siddharth Santurkar (siddharth.santurkar@ieee.org)
 Gaurav Sathe (gaurav.sathe@tcs.com)
@@ -288,6 +296,7 @@
 Tomasz Seweryn (tomasz.seweryn7@gmail.com)
 Dmitrii Shakshin (d.shakshin@gmail.com)
 Kulin Shah (m.kulin@gmail.com)
+Muyuan Shen (shmy315@gmail.com)
 Guowang Shi (shiguowang2007@gmail.com)
 Phillip Sitbon (phillip.sitbon@gmail.com)
 Pedro Silva (pmms@inesctec.pt)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/bindings/python/ns__init__.py ns-3.42/bindings/python/ns__init__.py
--- ns-3.41/bindings/python/ns__init__.py	2024-02-09 14:44:07.721789000 -0800
+++ ns-3.42/bindings/python/ns__init__.py	2024-05-29 15:29:46.832072700 -0700
@@ -82,11 +82,18 @@
         filter(lambda x: x not in SYSTEM_LIBRARY_DIRECTORIES, set(library_search_paths))
     )
 
+    # Exclude injected windows paths in case of WSL
+    # BTW, why Microsoft? Who had this brilliant idea?
+    library_search_paths = list(filter(lambda x: "/mnt/c/" not in x, library_search_paths))
+
     # Search for the core library in the search paths
     libraries = []
     for search_path in library_search_paths:
         if os.path.exists(search_path):
-            libraries += glob.glob("%s/**/*.%s*" % (search_path, LIBRARY_EXTENSION), recursive=True)
+            libraries += glob.glob(
+                "%s/**/*.%s*" % (search_path, LIBRARY_EXTENSION),
+                recursive=not os.path.exists(os.path.join(search_path, "ns3")),
+            )
 
     # Search system library directories (too slow for recursive search)
     for search_path in SYSTEM_LIBRARY_DIRECTORIES:
@@ -238,7 +245,12 @@
     # Should be the case when running from the source directory
     exec(open(lock_file).read(), {}, values)
     suffix = "-" + values["BUILD_PROFILE"] if values["BUILD_PROFILE"] != "release" else ""
-    modules = [module.replace("ns3-", "") for module in values["NS3_ENABLED_MODULES"]]
+    modules = list(
+        map(
+            lambda x: x.replace("ns3-", ""),
+            values["NS3_ENABLED_MODULES"] + values["NS3_ENABLED_CONTRIBUTED_MODULES"],
+        )
+    )
     prefix = values["out_dir"]
     libraries = {
         os.path.splitext(os.path.basename(x))[0]: x for x in os.listdir(os.path.join(prefix, "lib"))
@@ -508,11 +520,6 @@
     # We expose cppyy to consumers of this module as ns.cppyy
     setattr(cppyy.gbl.ns3, "cppyy", cppyy)
 
-    # To maintain compatibility with pybindgen scripts,
-    # we set an attribute per module that just redirects to the upper object
-    for module in modules:
-        setattr(cppyy.gbl.ns3, module.replace("-", "_"), cppyy.gbl.ns3)
-
     # Set up a few tricks
     cppyy.cppdef(
         """
@@ -558,81 +565,6 @@
     )
     setattr(cppyy.gbl.ns3, "LookupByNameFailSafe", cppyy.gbl.LookupByNameFailSafe)
 
-    def CreateObject(className):
-        try:
-            try:
-                func = "CreateObject%s" % re.sub("[<|>]", "_", className)
-                return getattr(cppyy.gbl, func)()
-            except AttributeError:
-                pass
-            try:
-                func = "Create%s" % re.sub("[<|>]", "_", className)
-                return getattr(cppyy.gbl, func)()
-            except AttributeError:
-                pass
-            raise AttributeError
-        except AttributeError:
-            try:
-                func = "CreateObject%s" % re.sub("[<|>]", "_", className)
-                cppyy.cppdef(
-                    """
-                            using namespace ns3;
-                            Ptr<%s> %s(){
-                                Ptr<%s> object = CreateObject<%s>();
-                                return object;
-                            }
-                            """
-                    % (className, func, className, className)
-                )
-            except Exception as e:
-                try:
-                    func = "Create%s" % re.sub("[<|>]", "_", className)
-                    cppyy.cppdef(
-                        """
-                                using namespace ns3;
-                                %s %s(){
-                                    %s object = %s();
-                                    return object;
-                                }
-                                """
-                        % (className, func, className, className)
-                    )
-                except Exception as e:
-                    exit(-1)
-        return getattr(cppyy.gbl, func)()
-
-    setattr(cppyy.gbl.ns3, "CreateObject", CreateObject)
-
-    def GetObject(parentObject, aggregatedObject):
-        # Objects have __cpp_name__ attributes, so parentObject
-        # should not have it while aggregatedObject can
-        if hasattr(parentObject, "__cpp_name__"):
-            raise Exception("Class was passed instead of an instance in parentObject")
-
-        aggregatedIsClass = hasattr(aggregatedObject, "__cpp_name__")
-        aggregatedIsString = type(aggregatedObject) == str
-        aggregatedIsInstance = not aggregatedIsClass and not aggregatedIsString
-
-        if aggregatedIsClass:
-            aggregatedType = aggregatedObject.__cpp_name__
-        if aggregatedIsInstance:
-            aggregatedType = aggregatedObject.__class__.__cpp_name__
-        if aggregatedIsString:
-            aggregatedType = aggregatedObject
-
-        cppyy.cppdef(
-            """using namespace ns3; template <> Ptr<%s> getAggregatedObject<%s>(Ptr<Object> parentPtr, %s param)
-               {
-                    return parentPtr->GetObject<%s>();
-               }
-            """
-            % (aggregatedType, aggregatedType, aggregatedType, aggregatedType)
-        )
-        return cppyy.gbl.getAggregatedObject(
-            parentObject, aggregatedObject if aggregatedIsClass else aggregatedObject.__class__
-        )
-
-    setattr(cppyy.gbl.ns3, "GetObject", GetObject)
     return cppyy.gbl.ns3
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/build-support/custom-modules/ns3-compiler-and-linker-support.cmake ns-3.42/build-support/custom-modules/ns3-compiler-and-linker-support.cmake
--- ns-3.41/build-support/custom-modules/ns3-compiler-and-linker-support.cmake	2024-02-09 14:44:07.721789000 -0800
+++ ns-3.42/build-support/custom-modules/ns3-compiler-and-linker-support.cmake	2024-05-29 15:29:46.832072700 -0700
@@ -47,6 +47,7 @@
 endif()
 
 set(GCC FALSE)
+set(GCC_WORKING_PEDANTIC_SEMICOLON 1)
 if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
   if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${GNU_MinVersion})
     message(
@@ -54,6 +55,26 @@
         "GNU ${CMAKE_CXX_COMPILER_VERSION} ${below_minimum_msg} ${GNU_MinVersion}"
     )
   endif()
+
+  # Check if pedantic throws warning in trailing semicolon after {} scope
+  # (frequently used to make macros look like functions)
+  unset(GCC_WORKING_PEDANTIC_SEMICOLON)
+  include(CheckCXXSourceCompiles)
+  set(CMAKE_REQUIRED_FLAGS "-Wall -Wpedantic -Werror")
+  check_cxx_source_compiles(
+    "
+      int test(){ return 0; };
+      int main(){
+        return test();
+      }
+  "
+    GCC_WORKING_PEDANTIC_SEMICOLON
+  )
+  unset(CMAKE_REQUIRED_FLAGS)
+  if("${GCC_WORKING_PEDANTIC_SEMICOLON}" STREQUAL "")
+    set(GCC_WORKING_PEDANTIC_SEMICOLON 0)
+  endif()
+
   if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.2.0"))
     # PCH causes weird errors on certain versions of GCC when C++20 is enabled
     # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106799
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/build-support/custom-modules/ns3-compiler-workarounds.cmake ns-3.42/build-support/custom-modules/ns3-compiler-workarounds.cmake
--- ns-3.41/build-support/custom-modules/ns3-compiler-workarounds.cmake	2024-02-09 14:44:07.721789000 -0800
+++ ns-3.42/build-support/custom-modules/ns3-compiler-workarounds.cmake	2024-05-29 15:29:46.832072700 -0700
@@ -14,31 +14,3 @@
 # Place, Suite 330, Boston, MA  02111-1307 USA
 #
 # Author: Gabriel Ferreira <gabrielcarvfer@gmail.com>
-
-include(CheckCXXSourceCompiles)
-
-# Some compilers (e.g. GCC < 9.1) do not link
-# std::filesystem/std::experimental::filesystem by default. If the sample
-# program can be linked, it means it is indeed linked by default. Otherwise, we
-# link it manually. https://en.cppreference.com/w/cpp/filesystem
-check_cxx_source_compiles(
-  "
-  #ifdef __has_include
-    #if __has_include(<filesystem>)
-      #include <filesystem>
-      namespace fs = std::filesystem;
-    #elif __has_include(<experimental/filesystem>)
-      #include <experimental/filesystem>
-      namespace fs = std::experimental::filesystem;
-    #else
-      #error \"No support for filesystem library\"
-    #endif
-  #endif
-  int main()
-  {
-    std::string path = \"/\";
-    return !fs::exists(path);
-  }
-  "
-  FILESYSTEM_LIBRARY_IS_LINKED
-)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/build-support/custom-modules/ns3-executables.cmake ns-3.42/build-support/custom-modules/ns3-executables.cmake
--- ns-3.41/build-support/custom-modules/ns3-executables.cmake	2024-02-09 14:44:07.725788800 -0800
+++ ns-3.42/build-support/custom-modules/ns3-executables.cmake	2024-05-29 15:29:46.832072700 -0700
@@ -102,15 +102,33 @@
     )
   endif()
 
+  # Check if library is not a ns-3 module library, and if it is, link when
+  # building static or monolib builds
+  set(libraries_to_always_link)
+  set(modules "${libs_to_build};${contrib_libs_to_build}")
+  foreach(lib ${BEXEC_LIBRARIES_TO_LINK})
+    # Remove the lib prefix if one exists
+    set(libless ${lib})
+    string(SUBSTRING "${libless}" 0 3 prefix)
+    if(prefix STREQUAL "lib")
+      string(SUBSTRING "${libless}" 3 -1 libless)
+    endif()
+    # Check if the library is not a ns-3 module
+    if(libless IN_LIST modules)
+      continue()
+    endif()
+    list(APPEND libraries_to_always_link ${lib})
+  endforeach()
+
   if(${NS3_STATIC} AND (NOT BEXEC_STANDALONE))
     target_link_libraries(
-      ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE_STATIC}
-      ${lib-ns3-static}
+      ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${libraries_to_always_link}
+      ${LIB_AS_NEEDED_PRE_STATIC} ${lib-ns3-static}
     )
   elseif(${NS3_MONOLIB} AND (NOT BEXEC_STANDALONE))
     target_link_libraries(
-      ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${LIB_AS_NEEDED_PRE}
-      ${lib-ns3-monolib} ${LIB_AS_NEEDED_POST}
+      ${BEXEC_EXECNAME_PREFIX}${BEXEC_EXECNAME} ${libraries_to_always_link}
+      ${LIB_AS_NEEDED_PRE} ${lib-ns3-monolib} ${LIB_AS_NEEDED_POST}
     )
   else()
     target_link_libraries(
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake ns-3.42/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake
--- ns-3.41/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake	2024-02-09 14:44:07.725788800 -0800
+++ ns-3.42/build-support/custom-modules/ns3-fetch-optional-modules-dependencies.cmake	2024-05-29 15:29:46.832072700 -0700
@@ -3,7 +3,7 @@
 ExternalProject_Add(
   brite_dep
   GIT_REPOSITORY https://gitlab.com/nsnam/BRITE.git
-  GIT_TAG 29c301e828d2a4f303b3d0c69360c987b02d0745
+  GIT_TAG 2a665ae11740a11afec1b068c2a45f21d901cf55
   PREFIX brite_dep
   BUILD_IN_SOURCE TRUE
   CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_OUTPUT_DIRECTORY}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/build-support/custom-modules/ns3-module-macros.cmake ns-3.42/build-support/custom-modules/ns3-module-macros.cmake
--- ns-3.41/build-support/custom-modules/ns3-module-macros.cmake	2024-02-09 14:44:07.725788800 -0800
+++ ns-3.42/build-support/custom-modules/ns3-module-macros.cmake	2024-05-29 15:29:46.836073000 -0700
@@ -179,10 +179,6 @@
       )
     endif()
 
-    if(NOT FILESYSTEM_LIBRARY_IS_LINKED)
-      list(APPEND BLIB_LIBRARIES_TO_LINK -lstdc++fs)
-    endif()
-
     # Enable examples as tests suites
     if(${ENABLE_EXAMPLES} AND ${ENABLE_TESTS})
       if(NOT ${XCODE})
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/build-support/macros-and-definitions.cmake ns-3.42/build-support/macros-and-definitions.cmake
--- ns-3.41/build-support/macros-and-definitions.cmake	2024-02-09 14:44:07.725788800 -0800
+++ ns-3.42/build-support/macros-and-definitions.cmake	2024-05-29 15:29:46.836073000 -0700
@@ -159,6 +159,21 @@
                                                         STREQUAL "default"
   )
     set(cmakeBuildType relwithdebinfo)
+    # Do not use optimized for size builds on MacOS See issue #1065:
+    # https://gitlab.com/nsnam/ns-3-dev/-/issues/1065
+    if(NOT (DEFINED APPLE))
+      string(REPLACE "-O2" "-Os" CMAKE_CXX_FLAGS_RELWITHDEBINFO
+                     "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}"
+      )
+    endif()
+    # Do not use -Os for gcc 9 default builds due to a bug in gcc that can
+    # result  in extreme memory usage. See MR !1955
+    # https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/1955
+    if(GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "10.0.0")
+      string(REPLACE "-Os" "-O2" CMAKE_CXX_FLAGS_RELWITHDEBINFO
+                     "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}"
+      )
+    endif()
     set(CMAKE_CXX_FLAGS_DEFAULT ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
     add_definitions(-DNS3_BUILD_PROFILE_DEBUG)
   elseif(${cmakeBuildType} STREQUAL "release")
@@ -214,6 +229,9 @@
       endif()
     else()
       add_compile_options(-Wall) # -Wextra
+      if(${GCC_WORKING_PEDANTIC_SEMICOLON})
+        add_compile_options(-Wpedantic)
+      endif()
       if(${NS3_WARNINGS_AS_ERRORS})
         add_compile_options(-Werror -Wno-error=deprecated-declarations)
       endif()
@@ -371,7 +389,9 @@
   endif()
 
   if(${NS3_SANITIZE})
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,leak,undefined")
+    set(CMAKE_CXX_FLAGS
+        "${CMAKE_CXX_FLAGS} -fsanitize=address,leak,undefined -fno-sanitize-recover=all"
+    )
   endif()
 
   if(${NS3_SANITIZE_MEMORY})
@@ -572,6 +592,7 @@
     endif()
   endif()
 
+  set(LIBXML2_FOUND FALSE)
   if(${NS3_STATIC})
     # Warn users that they may be using shared libraries, which won't produce a
     # standalone static library
@@ -965,7 +986,7 @@
   # return variable
   check_deps(
     sphinx_docs_missing_deps CMAKE_PACKAGES Sphinx
-    EXECUTABLES epstopdf pdflatex latexmk convert dvipng
+    EXECUTABLES epstopdf pdflatex latexmk convert dvipng dia
   )
   if(sphinx_docs_missing_deps)
     message(
@@ -1246,19 +1267,26 @@
         <cstdlib>
         <cstring>
         <exception>
+        <deque>
         <fstream>
+        <functional>
         <iostream>
         <limits>
         <list>
         <map>
         <math.h>
         <ostream>
+        <queue>
         <set>
         <sstream>
         <stdint.h>
         <stdlib.h>
         <string>
+        <tuple>
+        <typeinfo>
+        <type_traits>
         <unordered_map>
+        <utility>
         <vector>
     )
     add_library(
@@ -1269,7 +1297,11 @@
       stdlib_pch${build_profile_suffix} PUBLIC
       "${precompiled_header_libraries}"
     )
-    add_library(stdlib_pch ALIAS stdlib_pch${build_profile_suffix})
+
+    # Alias may collide with actual pch in builds without suffix (e.g. release)
+    if(NOT TARGET stdlib_pch)
+      add_library(stdlib_pch ALIAS stdlib_pch${build_profile_suffix})
+    endif()
 
     add_executable(
       stdlib_pch_exec ${PROJECT_SOURCE_DIR}/build-support/empty-main.cc
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/CHANGES.md ns-3.42/CHANGES.md
--- ns-3.41/CHANGES.md	2024-02-09 14:44:07.721789000 -0800
+++ ns-3.42/CHANGES.md	2024-05-29 15:30:03.724115800 -0700
@@ -13,6 +13,50 @@
 
 This file is a best-effort approach to solving this issue; we will do our best but can guarantee that there will be things that fall through the cracks, unfortunately. If you, as a user, can suggest improvements to this file based on your experience, please contribute a patch or drop us a note on ns-developers mailing list.
 
+Changes from ns-3.41 to ns-3.42
+-------------------------------
+
+### New API
+* (antenna) Added `CircularApertureAntennaModel` class which characterizes the antenna gain pattern of the reflector antenna with circular aperture described in 3GPP TR 38.811 v15.4.0, Section 6.4.1
+* (core) Objects now can be aggregated to multiple objects though the `Object::UnidirectionalAggregateObject` function. Objects aggregated in such a way can not use `GetObject` to access the objects they are aggregated to.
+* (core) Added `TestVector` iterators and dot product operator for `Vector2D` and `Vector3D` types
+* (mobility) Added a new mobility model `GeocentricConstantPositionMobilityModel` for orbital and/or aerial nodes, and coordinate conversion methods between geocentric and topocentric coordinate systems
+* (propagation, spectrum)  Added 3GPP 38.811 Non-Terrestrial Networks (NTNs) channel model. Specifically, the large-scale phenomena have been implemented by extending `ThreeGppPropagationLossModel` with classes representing the various NTN propagation scenarios  (Dense Urban, Urban, Rural and Suburban), while the frequency-dependent phenomena have been implemented by defining the corresponding scenarios in `ThreeGppChannelModel`.
+* (network) Added `ApplicationHelper` helper class to create and install applications, removing redundant code in existing helpers and reducing the burden to add yet another helper when a new application model is added.
+* (wifi) Added a new **SingleRtsPerTxop** attribute to `WifiDefaultProtectionManager`, which, if set to true, prevents to use protection mechanisms (RTS or MU-RTS) more than once in a TXOP (unless required for specific purposes, such as transmitting an Initial Control Frame to an EMLSR client).
+* (wifi) Added a new **RtsCtsTxDurationThresh** to `WifiRemoteStationManager` to enable RTS/CTS protection based on the TX duration of the data frame. Both the value of this attribute and the value of the existing **RtsCtsThreshold** attribute are evaluated: if either of the thresholds (or both) is exceeded, RTS/CTS is used.
+* (wifi) New trace helper `WifiPhyRxTraceHelper` for detailed tracing of Wi-Fi Phy reception events
+* (wifi) New trace sources `WifiPhy::SignalTransmission`, `SpectrumWifiPhy::SignalArrival`, and `YansWifiPhy::SignalArrival`
+* (wifi) New trace sources `WifiPhyStateHelper::RxOutcome` and`WifiPhy::PhyRxPpduDrop`, to support additional tracing.
+
+### Changes to existing API
+
+* (applications) Applications have a new Attribute to set the IPv4 ToS field.
+* (core) Deprecated enum `TestDuration` in `TestCase` class. It has been replaced by enum class `Duration`.
+* (core) In `TestSuite` class, deprecated `ALL`, `UNIT`, `SYSTEM`, `EXAMPLE` and `PERFORMANCE`. They have been replaced by `Type::ALL`, `Type::UNIT`, `Type::SYSTEM`, `Type::EXAMPLE` and `Type::PERFORMANCE`, respectively.
+* (core) Deprecated `EventId::IsRunning()`. It has been replaced with `EventId::IsPending()`.
+* (energy) The model library code of the energy module now uses the nested namespace `energy`.
+* (lr-wpan) `MacPibAttributeIdentifier` attribute ids are now standard compliant.
+* (lr-wpan) Multiple new identifiers added to `MacPibAttributeIdentifier`.
+* (lr-wpan) Adds standard version comments to `MLME-GET.request` function.
+* (lr-wpan) In the MAC layer, renamed `m_selfExt` to the variable `m_macExtendedAddress` to make it consistent with the standard specification.
+* (lr-wpan) The Lr-wpan module now uses the namespace `lrwpan`.
+* (lr-wpan) The model library code of the lr-wpan module now uses the nested namespace `lrwpan`.
+* (lr-wpan) The `LrWpan` prefix of variables, structs and enumerations in the PHY and MAC was shorten to reflect the recent namespace change.
+* (wifi) Deprecated `WIFI_TID_TO_LINK_MAPPING_{NOT_SUPPORTED,SAME_LINK_SET,ANY_LINK_SET}`. They have been replaced by `WifiTidToLinkMappingNegSupport::{NOT_SUPPORTED,SAME_LINK_SET,ANY_LINK_SET}`, respectively.
+* (wifi) Deprecated `{IDLE, CCA_BUSY, TX, RX, SWITCHING, SLEEP, OFF}`. They have been replaced by `WifiPhyState::{IDLE, CCA_BUSY, TX, RX, SWITCHING, SLEEP, OFF}`, respectively.
+* (wifi) Obsoleted **Txop** attributes `MinCw`, `MaxCw`, `Aifsn` and `TxopLimit`. The corresponding attributes for multi-link devices (`MinCws`, `MaxCws`, `Aifsns` and `TxopLimits`) can be used instead.
+
+### Changes to build system
+
+* Removed support of the `experimental/filesystem` library, in favor of the official `filesystem` library.
+* Fixed static and monolib builds when linking to a non ns-3 module library.
+
+### Changed behavior
+
+* (mobility) Fixed the corner rebound direction in `RandomWalk2d[Outdoor]MobilityModel` and the initial direction in case of node starting from a border or corner.
+* (tcp) TcpCubic and TcpLinuxReno will no longer grow their congestion window when application-limited, now matching Linux behavior
+
 Changes from ns-3.40 to ns-3.41
 -------------------------------
 
@@ -41,6 +85,7 @@
   ```cpp
   MakeEnumAccessor<Test_e>(&AttributeObjectTest::m_enum),
   ```
+
 * (internet) Deprecated `Ipv4::WeakEsModel` and `Ipv4::GetWeakEsModel()`, `Ipv4::SetWeakEsModel(bool)` methods. Moved `Ipv6L3Protocol::StrongEndSystemModel` to `Ipv6::StrongEndSystemModel` and added `Ipv4::StrongEndSystemModel` with corresponding `GetStrongEndSystemModel()` and `SetStrongEndSystemModel(bool)` methods to improve end system model configuration options.
 * (lr-wpan) Change the CapabilityField parameter in `LrWpanMac::MlmeAssociateRequest` and `LrWpanMac::MlmeAssociateIndication` to a standard bitmap.
 * (lr-wpan) Change the MAC SuperframeField usage to a standard bitmap, this change impact parameters in the `BeaconPayloadHeader`.
@@ -68,6 +113,7 @@
 * Added guard rails for scratch targets missing or containing more than one `main` function.
 
 ### Changed behavior
+
 * (sixlowpan) Now uses RFC 7973 Ethertype by default
 * (spectrum) SpectrumChannel objects and the loss/delay models attached are now automatically initialized (Object::Initialize) at time zero
 * (tcp) TCP Cubic (the default congestion control in ns-3) now supports TCP-friendliness by default (see RFC 9438 Section 4.3), making the congestion window growth somewhat more aggressive.  This follows the default Linux behavior.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/.clang-tidy ns-3.42/.clang-tidy
--- ns-3.41/.clang-tidy	2024-02-09 14:44:07.717788700 -0800
+++ ns-3.42/.clang-tidy	2024-05-29 15:29:46.824072800 -0700
@@ -2,6 +2,7 @@
   -*,
   bugprone-argument-comment,
   bugprone-bool-pointer-implicit-conversion,
+  bugprone-branch-clone,
   bugprone-inaccurate-erase,
   bugprone-move-forwarding-reference,
   bugprone-redundant-branch-condition,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/CMakeLists.txt ns-3.42/CMakeLists.txt
--- ns-3.41/CMakeLists.txt	2024-02-09 14:44:07.721789000 -0800
+++ ns-3.42/CMakeLists.txt	2024-05-29 15:29:46.828072800 -0700
@@ -13,7 +13,7 @@
 # minimum compiler versions
 set(AppleClang_MinVersion 11.0.0)
 set(Clang_MinVersion 10.0.0)
-set(GNU_MinVersion 9.0.0)
+set(GNU_MinVersion 9.1.0)
 
 # common options
 option(NS3_ASSERT "Enable assert on failure" OFF)
@@ -107,21 +107,6 @@
       "List of modules that should have their examples and tests built (e.g. lte;wifi)"
 )
 
-if(${NS3_CCACHE})
-  # Use ccache if available
-  mark_as_advanced(CCACHE)
-  find_program(CCACHE ccache)
-  if(NOT ("${CCACHE}" STREQUAL "CCACHE-NOTFOUND"))
-    message(STATUS "CCache is enabled.")
-    set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
-    execute_process(
-      COMMAND
-        ${CCACHE} --set-config
-        sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime
-    )
-  endif()
-endif()
-
 # Include macros used below
 include(build-support/macros-and-definitions.cmake)
 
@@ -143,6 +128,21 @@
   ns3rc_enabled_modules ns3rc_disabled_modules
 )
 
+if(${NS3_CCACHE})
+  # Use ccache if available
+  mark_as_advanced(CCACHE)
+  find_program(CCACHE ccache)
+  if(NOT ("${CCACHE}" STREQUAL "CCACHE-NOTFOUND"))
+    message(STATUS "CCache is enabled.")
+    set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
+    execute_process(
+      COMMAND
+        ${CCACHE} --set-config
+        sloppiness=pch_defines,time_macros,include_file_mtime,include_file_ctime
+    )
+  endif()
+endif()
+
 # ##############################################################################
 # Process options                     #
 # ##############################################################################
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/contributing/Makefile ns-3.42/doc/contributing/Makefile
--- ns-3.41/doc/contributing/Makefile	2024-02-09 14:44:07.725788800 -0800
+++ ns-3.42/doc/contributing/Makefile	2024-05-29 15:29:46.836073000 -0700
@@ -2,7 +2,7 @@
 #
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/contributing/source/coding-style.rst ns-3.42/doc/contributing/source/coding-style.rst
--- ns-3.41/doc/contributing/source/coding-style.rst	2024-02-09 14:44:07.725788800 -0800
+++ ns-3.42/doc/contributing/source/coding-style.rst	2024-05-29 15:29:46.836073000 -0700
@@ -1550,6 +1550,68 @@
     // Avoid repeating the type name "MyClass" in std::less<>
     std::map<MyClass, int, std::less<MyClass>> myMap;
 
+- In conditional control blocks (i.e., if-else and switch-case), avoid declaring multiple
+  branch conditions with the same content to avoid duplicating code.
+
+  In if-else blocks, prefer grouping the identical bodies in a single if condition with a
+  disjunction of the multiple conditions.
+
+  .. sourcecode:: cpp
+
+    if (condition1)
+    {
+        Foo();
+    }
+    else if (condition2)
+    {
+        // Same body as condition 1
+        Foo();
+    }
+    else
+    {
+        Bar();
+    }
+
+    // Prefer grouping the two conditions
+    if (condition1 || condition2)
+    {
+        Foo();
+    }
+    else
+    {
+        Bar();
+    }
+
+  In switch-case blocks, prefer grouping identical ``case`` labels by removing the duplicate
+  bodies of the former ``case`` labels.
+
+  .. sourcecode:: cpp
+
+    switch (condition)
+    {
+    case 1:
+        Foo();
+        break;
+    case 2: // case 2 has the same body as case 1
+        Foo();
+        break;
+    case 3:
+        Bar();
+        break;
+    }
+
+    switch (condition)
+    {
+    // Group identical cases by removing the content of case 1 and letting it fallthrough to case 2
+    case 1:
+    case 2:
+        Foo();
+        break;
+    case 3:
+        Bar();
+        break;
+    }
+
 
 CMake file formatting
 *********************
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/contributing/source/conf.py ns-3.42/doc/contributing/source/conf.py
--- ns-3.41/doc/contributing/source/conf.py	2024-02-09 14:45:45.430484000 -0800
+++ ns-3.42/doc/contributing/source/conf.py	2024-05-29 15:30:03.724115800 -0700
@@ -49,9 +49,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = "ns-3.41"
+version = "ns-3.42"
 # The full version, including alpha/beta/rc tags.
-release = "ns-3.41"
+release = "ns-3.42"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/doxygen.conf ns-3.42/doc/doxygen.conf
--- ns-3.41/doc/doxygen.conf	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/doxygen.conf	2024-05-29 15:29:46.840072900 -0700
@@ -461,7 +461,7 @@
 # the optimal cache size from a speed point of view.
 # Minimum value: 0, maximum value: 9, default value: 0.
 
-LOOKUP_CACHE_SIZE      = 2
+LOOKUP_CACHE_SIZE      = 4
 
 # The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
 # during processing. When set to 0 doxygen will based this on the number of
@@ -1086,7 +1086,7 @@
 # Fortran comments will always remain visible.
 # The default value is: YES.
 
-STRIP_CODE_COMMENTS    = YES
+STRIP_CODE_COMMENTS    = NO
 
 # If the REFERENCED_BY_RELATION tag is set to YES then for each documented
 # entity all documented functions referencing it will be listed.
@@ -2232,7 +2232,7 @@
 
 ## Allow doxygen to find generated include files, such as ns3/core-config.h
 
-INCLUDE_PATH           = build
+INCLUDE_PATH           = build/include
 
 # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
 # patterns (like *.h and *.hpp) to filter out the header-files in the
@@ -2297,7 +2297,11 @@
                          ATTRIBUTE_VALUE_DEFINE_WITH_NAME \
                          ATTRIBUTE_VALUE_IMPLEMENT \
                          ATTRIBUTE_VALUE_IMPLEMENT_WITH_NAME \
-                         NS_UNUSED_GLOBAL
+                         NS_UNUSED_GLOBAL \
+                         NS_DEPRECATED \
+                         NS_DEPRECATED_3_42 \
+                         NS_DEPRECATED_3_41 \
+                         NS_DEPRECATED_3_40
 
 # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
 # remove all references to function-like macros that are alone on a line, have
@@ -2571,7 +2575,7 @@
 # The default value is: png.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-DOT_IMAGE_FORMAT       = png
+DOT_IMAGE_FORMAT       = SVG
 
 # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
 # enable generation of interactive SVG images that allow zooming and panning.
@@ -2583,7 +2587,7 @@
 # The default value is: NO.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-INTERACTIVE_SVG        = NO
+INTERACTIVE_SVG        = YES
 
 # The DOT_PATH tag can be used to specify the path where the dot tool can be
 # found. If left blank, it is assumed the dot tool can be found in the path.
@@ -2694,4 +2698,3 @@
 
 # Disable dark mode in the generated HTML in Doxygen 1.9.6 or greater.
 # HTML_COLORSTYLE        = LIGHT
-
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/doxygen.warnings.report.sh ns-3.42/doc/doxygen.warnings.report.sh
--- ns-3.41/doc/doxygen.warnings.report.sh	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/doxygen.warnings.report.sh	2024-05-29 15:29:46.840072900 -0700
@@ -248,10 +248,10 @@
 
 #   Functions with varying numbers of arguments
 #   Explicit template instantiation declaration
-REappend filter_blacklistRE "MakeCallback< ObjectBase \\* >(ObjectBase \\*"
+# REappend filter_blacklistRE "MakeCallback< ObjectBase \\* >(ObjectBase \\*"
 
 #   ATTRIBUTE_HELPER_CPP( and _HEADER(
-REappend filter_blacklistRE "ATTRIBUTE_HELPER_\\(CPP\\|HEADER\\)"
+# REappend filter_blacklistRE "ATTRIBUTE_HELPER_\\(CPP\\|HEADER\\)"
 
 # Filter out regular expression for black list, -e, -t and -F
 filter_outRE=""
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/Makefile ns-3.42/doc/installation/Makefile
--- ns-3.41/doc/installation/Makefile	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/installation/Makefile	2024-05-29 15:29:46.840072900 -0700
@@ -2,7 +2,7 @@
 #
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/source/conf.py ns-3.42/doc/installation/source/conf.py
--- ns-3.41/doc/installation/source/conf.py	2024-02-09 14:45:45.430484000 -0800
+++ ns-3.42/doc/installation/source/conf.py	2024-05-29 15:30:03.724115800 -0700
@@ -49,9 +49,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = "ns-3.41"
+version = "ns-3.42"
 # The full version, including alpha/beta/rc tags.
-release = "ns-3.41"
+release = "ns-3.42"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/source/linux.rst ns-3.42/doc/installation/source/linux.rst
--- ns-3.41/doc/installation/source/linux.rst	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/installation/source/linux.rst	2024-05-29 15:29:46.840072900 -0700
@@ -103,9 +103,14 @@
 Python bindings
 ===============
 
-Python requires `Cppyy, <https://cppyy.readthedocs.io/en/latest/installation.html>` and specifically, version 2.4.2 is the latest version known to work with ns-3 at this time.
+Python requires `Cppyy, <https://cppyy.readthedocs.io/en/latest/installation.html>` and specifically,
+version 3.1.2 is the latest version known to work with ns-3 at this time.
 
-ns-3.37 and newer::
+ns-3.42 and newer::
+
+  python3 -m pip install --user cppyy==3.1.2
+
+ns-3.37-3.41::
 
   python3 -m pip install --user cppyy==2.4.2
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/source/macos.rst ns-3.42/doc/installation/source/macos.rst
--- ns-3.41/doc/installation/source/macos.rst	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/installation/source/macos.rst	2024-05-29 15:29:46.840072900 -0700
@@ -64,7 +64,7 @@
   +=============================+========================+===================================+
   | Compiler cache optimization | ``ccache``             | ``ccache``                        |
   +-----------------------------+------------------------+-----------------------------------+
-  | Code linting                | ``clang-format llvm``  |  clang-format included with       |
+  | Code linting                | ``clang-format llvm``  | clang-format included with        |
   |                             |                        | ``clang``, need to select         |
   |                             |                        | ``clang-XX llvm-XX`` versions     |
   +-----------------------------+------------------------+-----------------------------------+
@@ -123,7 +123,8 @@
   | Emulation with virtual      |                                  |                          |
   | machines                    | Not available for macOS          | Not available for macOS  |
   +-----------------------------+----------------------------------+--------------------------+
-  | Support for openflow        | ``boost``                        | ``boost``                |
+  | Support for openflow,       | ``boost``                        | ``boost``                |
+  | CircularApertureAntennaModel|                                  |                          |
   +-----------------------------+----------------------------------+--------------------------+
 
 Caveats and troubleshooting
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/source/quick-start.rst ns-3.42/doc/installation/source/quick-start.rst
--- ns-3.41/doc/installation/source/quick-start.rst	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/installation/source/quick-start.rst	2024-05-29 15:29:46.840072900 -0700
@@ -80,13 +80,13 @@
 
 There are two main options:
 
-1. Download a release tarball.  This will unpack to a directory such as ``ns-allinone-3.41``
+1. Download a release tarball.  This will unpack to a directory such as ``ns-allinone-3.42``
 containing |ns3| and some other programs.  Below is a command-line download using ``wget``,
 but a browser download will also work::
 
-  $ wget https://www.nsnam.org/releases/ns-allinone-3.41.tar.bz2
-  $ tar xfj ns-allinone-3.41.tar.bz2
-  $ cd ns-allinone-3.41/ns-3.41
+  $ wget https://www.nsnam.org/releases/ns-allinone-3.42.tar.bz2
+  $ tar xfj ns-allinone-3.42.tar.bz2
+  $ cd ns-allinone-3.42/ns-3.42
 
 2. Clone |ns3| from the Git repository.  The ``ns-3-allinone`` can be cloned, as well as
 ``ns-3-dev`` by itself.  Below, we illustrate the latter::
@@ -99,7 +99,7 @@
 the |ns3| ``master`` branch, which is a development branch.  All |ns3| releases are tagged
 in Git, so if you would then like to check out a past release, you can do so as follows::
 
-  $ git checkout -b ns-3.41-release ns-3.41
+  $ git checkout -b ns-3.42-release ns-3.42
 
 In this quick-start, we are omitting download and build instructions for optional |ns3| modules,
 the ``NetAnim`` animator, Python bindings, and ``NetSimulyzer``.  The
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/source/system.rst ns-3.42/doc/installation/source/system.rst
--- ns-3.41/doc/installation/source/system.rst	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/installation/source/system.rst	2024-05-29 15:29:46.840072900 -0700
@@ -140,8 +140,10 @@
 Python bindings (ns-3.37 and newer)
 ===================================
 
-|ns3| Python support now uses `cppyy <https://cppyy.readthedocs.io/en/latest/>`_.  Version 2.4.2
-is the most recent supported cppyy release; version 3.0.0 is not currently supported.
+|ns3| Python support now uses `cppyy <https://cppyy.readthedocs.io/en/latest/>`_.  Version 3.1.2
+is the most recent supported cppyy release since ns-3.42.
+
+Cppyy version 2.4.2 should be used from ns-3.37 up to 3.41.
 
 Due to an `upstream limitation with cppyy <https://github.com/wlav/cppyy/issues/150>`_, Python bindings do not work on macOS machines with Apple silicon (M1 and M2 processors).
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/installation/source/windows.rst ns-3.42/doc/installation/source/windows.rst
--- ns-3.41/doc/installation/source/windows.rst	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/installation/source/windows.rst	2024-05-29 15:29:46.840072900 -0700
@@ -175,7 +175,7 @@
 texlive configuration profile below. You can change the installation directory (starting with
 ``C:/texlive/2022``).
 
-.. sourcecode:: raw
+.. sourcecode:: text
 
     selected_scheme scheme-custom
     TEXDIR C:/texlive/2022
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/Makefile ns-3.42/doc/manual/Makefile
--- ns-3.41/doc/manual/Makefile	2024-02-09 14:44:07.729788800 -0800
+++ ns-3.42/doc/manual/Makefile	2024-05-29 15:29:46.840072900 -0700
@@ -46,6 +46,7 @@
 	source/troubleshoot.rst \
 	source/utilities.rst \
 	source/working-with-cmake.rst \
+	source/working-with-docker.rst \
 	source/working-with-git.rst \
 	source/working-with-gitlab-ci-local.rst \
 	${SRC}/stats/doc/data-collection.rst \
@@ -135,7 +136,7 @@
 	@if test x$($@_width) != x; then $(RESCALE) $($@_width) $@ ; fi
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/conf.py ns-3.42/doc/manual/source/conf.py
--- ns-3.41/doc/manual/source/conf.py	2024-02-09 14:45:45.430484000 -0800
+++ ns-3.42/doc/manual/source/conf.py	2024-05-29 15:30:03.724115800 -0700
@@ -74,16 +74,16 @@
 # built documents.
 #
 # The short X.Y version.
-version = "ns-3.41"
+version = "ns-3.42"
 # The full version, including alpha/beta/rc tags.
-release = "ns-3.41"
+release = "ns-3.42"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+# language = None
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/develop.rst ns-3.42/doc/manual/source/develop.rst
--- ns-3.41/doc/manual/source/develop.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/develop.rst	2024-05-29 15:29:46.872073000 -0700
@@ -17,3 +17,4 @@
    documentation
    profiling
    working-with-gitlab-ci-local
+   working-with-docker
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/enable-tests.rst ns-3.42/doc/manual/source/enable-tests.rst
--- ns-3.41/doc/manual/source/enable-tests.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/enable-tests.rst	2024-05-29 15:29:46.872073000 -0700
@@ -181,14 +181,14 @@
 As seen above, the following command only builds the requested modules (core and wifi),
 plus any modules that are implicitly needed (e.g., network), and the resulting compatible examples and tests:
 
-.. sourcecode:: terminal
+.. sourcecode:: console
 
   ./ns3 configure --enable-modules="wifi;core" --enable-examples --enable-tests
 
 However, when developing a new module, you may prefer to use the following alternative, which builds
 all module libraries, but will filter out any examples and tests from modules that are not explicitly listed.
 
-.. sourcecode:: terminal
+.. sourcecode:: console
 
   ./ns3 configure --filter-module-examples-and-tests="wifi;core" --enable-examples --enable-tests
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/events.rst ns-3.42/doc/manual/source/events.rst
--- ns-3.41/doc/manual/source/events.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/events.rst	2024-05-29 15:29:46.872073000 -0700
@@ -81,7 +81,7 @@
 In other words tied events are handled in FIFO order.
 
 Note that concurrent events (events that happen at the very same time)
-are unlikely in a real system - not to say impossible. In |ns-3|
+are unlikely in a real system - not to say impossible. In |ns3|
 concurrent events are common for a number of reasons, one of them
 being the time representation. While developing a model this must
 be carefully taken into account.
@@ -289,14 +289,14 @@
 
 or by using a command line argument
 
-.. sourcecode:: terminal
+.. sourcecode:: console
 
   $ ./ns3 run "...  --SimulatorImplementationType=ns3::DistributedSimulatorImpl"
 
 In addition to the basic simulator engines there is a general facility used
 to build "adapters" which provide small behavior modifications to one of
 the core `SimulatorImpl` engines.  The adapter base class is
-`SimulatorAdapter`, itself derived from `SimulatorImpl`.  `SimluatorAdapter`
+`SimulatorAdapter`, itself derived from `SimulatorImpl`.  `SimulatorAdapter`
 uses the `PIMPL (pointer to implementation) <https://en.cppreference.com/w/cpp/language/pimpl>`_
 idiom to forward all calls to the configured base simulator engine.
 This makes it easy to provide small customizations
@@ -305,7 +305,7 @@
 
 There are few places where adapters are used currently:
 
-*  `ReadltimeSimulatorImpl`  This adapter attempts to execute in real time
+*  `RealtimeSimulatorImpl`  This adapter attempts to execute in real time
    by pacing the wall clock evolution.  This pacing is "best effort",
    meaning actual event execution may not occur exactly in sync, but
    close to it. This engine is normally only used with the
@@ -413,5 +413,5 @@
 +------------------------+-------------------------------------+-------------+--------------+----------+--------------+
 | MapScheduler           | `st::map`                           | Logarithmic | Constant     | 40 bytes | 32 bytes     |
 +------------------------+-------------------------------------+-------------+--------------+----------+--------------+
-| PriorityQueueScheduler | `std::priority_queue<,std::vector>` | Logarithimc | Logarithims  | 24 bytes | 0            |
+| PriorityQueueScheduler | `std::priority_queue<,std::vector>` | Logarithmic | Logarithms   | 24 bytes | 0            |
 +------------------------+-------------------------------------+-------------+--------------+----------+--------------+
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/how-to-write-tests.rst ns-3.42/doc/manual/source/how-to-write-tests.rst
--- ns-3.41/doc/manual/source/how-to-write-tests.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/how-to-write-tests.rst	2024-05-29 15:29:46.872073000 -0700
@@ -30,7 +30,7 @@
 * What type of test it will be (Build Verification Test, Unit Test,
   System Test, or Performance Test)
 * Where the test code will live (either in an existing ns-3 module or
-  separately in src/test/ directory).  You will have to edit the wscript
+  separately in src/test/ directory).  You will have to edit the CMakeLists.txt
   file in that directory to compile your new code, if it is a new file.
 
 A program called ``utils/create-module.py`` is a good starting point.
@@ -44,14 +44,14 @@
 the model that you want to test.  You can also edit things such as a
 more descriptive test case name.
 
-You also need to add a block into your wscript to get this test to
+You also need to add a block into your CMakeLists.txt to get this test to
 compile:
 
-.. sourcecode:: python
+.. sourcecode:: cmake
 
-    module_test.source = [
-        'test/router-test-suite.cc',
-        ]
+    set(test_sources
+        test/router-test-suite.cc
+    )
 
 Before you actually start making this do useful things, it may help
 to try to run the skeleton.  Make sure that ns-3 has been configured with
@@ -61,7 +61,7 @@
 ::
 
   RouterTestSuite::RouterTestSuite()
-    : TestSuite("router", UNIT)
+    : TestSuite("router", Type::UNIT)
 
 Try this command:
 
@@ -137,7 +137,7 @@
 designed to run an example and compare the output with a specified
 known "good" reference file.  To use an example program as a test you
 need to create a test suite file and add it to the appropriate list in
-your module wscript file. The "good" output reference file needs to be
+your module CMakeLists.txt file. The "good" output reference file needs to be
 generated for detecting regressions.
 
 If you are thinking about using this class, strongly consider using a
@@ -164,16 +164,25 @@
 same example is run twice with different arguments.
 
 You then need to add that newly created test suite file to the list of
-test sources in ``mymodule/wscript``.  Building of examples
+test sources in ``mymodule/CMakeLists.txt``.  Building of examples
 is an option so you need to guard the inclusion of the test suite:
 
-.. sourcecode:: python
+.. sourcecode:: cmake
 
-   if (bld.env['ENABLE_EXAMPLES']):
-      module.source.append('model/mymodule-examples-test-suite.cc')
+   set(example_as_test_suite)
+   if(${ENABLE_EXAMPLES})
+     set(example_as_test_suite
+         test/mymodule-examples-test-suite.cc
+     )
+   endif()
+
+and then later
+
+.. sourcecode:: cmake
+
+   set(test_sources
+      ${example_as_test_suite}
 
-Since you modified a wscript file you need to reconfigure and rebuild
-everything.
 
 You just added new tests so you will need to generate the "good"
 output reference files that will be used to verify the example:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/new-modules.rst ns-3.42/doc/manual/source/new-modules.rst
--- ns-3.41/doc/manual/source/new-modules.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/new-modules.rst	2024-05-29 15:29:46.872073000 -0700
@@ -162,7 +162,7 @@
 with a single test case consisting of the class ``NewModuleTestCase1``::
 
   NewModuleTestSuite::NewModuleTestSuite()
-    : TestSuite("new-module", UNIT)
+    : TestSuite("new-module", Type::UNIT)
   {
     AddTestCase(new NewModuleTestCase1);
   }
@@ -372,33 +372,38 @@
   # A list of C++ examples to run in order to ensure that they remain
   # buildable and runnable over time.  Each tuple in the list contains
   #
-  #     (example_name, do_run, do_valgrind_run).
+  #     (example_name, do_run, do_valgrind_run, fullness).
   #
   # See test.py for more information.
   cpp_examples = [
-      ("adhoc-aloha-ideal-phy", "True", "True"),
-      ("adhoc-aloha-ideal-phy-with-microwave-oven", "True", "True"),
-      ("adhoc-aloha-ideal-phy-matrix-propagation-loss-model", "True", "True"),
+      ("adhoc-aloha-ideal-phy", "True", "True", "QUICK"),
+      ("adhoc-aloha-ideal-phy-with-microwave-oven", "True", "True", "QUICK"),
+      ("adhoc-aloha-ideal-phy-matrix-propagation-loss-model", "True", "True", "QUICK"),
   ]
 
   # A list of Python examples to run in order to ensure that they remain
   # runnable over time.  Each tuple in the list contains
   #
-  #     (example_name, do_run).
+  #     (example_name, do_run, fullness).
   #
   # See test.py for more information.
   python_examples = [
-      ("sample-simulator.py", "True"),
+      ("sample-simulator.py", "True", "QUICK"),
   ]
 
 As indicated in the comment, each entry in the C++ list of examples to run
-contains the tuple ``(example_name, do_run, do_valgrind_run)``, where
+contains the tuple ``(example_name, do_run, do_valgrind_run, fullness)``, where
 
 * ``example_name`` is the executable to be run,
 * ``do_run`` is a condition under which to run the example, and
 * ``do_valgrind_run`` is a condition under which to run the example
   under valgrind.  (This is needed because NSC causes illegal instruction
   crashes with some tests when they are run under valgrind.)
+* ``fullness`` is the optional classification of how long the example takes to
+  run, like the :doc:`Tests <tests>` fullness specifier. from
+  fastest to slowest the possible options are: ``"QUICK"``,
+  ``"EXTENSIVE"``, and ``"TAKES_FOREVER"``. If no value is
+  provided, ``"QUICK"`` is used.
 
 Note that the two conditions are Python statements that
 can depend on ``ns3`` configuration variables.  For example, using the
@@ -406,20 +411,22 @@
 
 .. sourcecode:: python
 
-    ("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False"),
+    ("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False", "QUICK"),
 
 Each entry in the Python list of examples to run contains the tuple
-``(example_name, do_run)``, where, as for the C++ examples,
+``(example_name, do_run, fullness)``, where, as for the C++ examples,
 
 * ``example_name`` is the Python script to be run, and
 * ``do_run`` is a condition under which to run the example.
+* ``fullness`` is the same as ``fullness`` for C++ examples.
+  If no value is provided, ``"QUICK"`` is used
 
 Again, the condition is a Python statement that can
 depend on ``ns3`` configuration variables.  For example,
 
 .. sourcecode:: python
 
-    ("brite-generic-example", "ENABLE_BRITE == True", "False"),
+    ("brite-generic-example.py", "ENABLE_BRITE == True", "QUICK"),
 
 
 Step 8 - Configure and Build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/profiling.rst ns-3.42/doc/manual/source/profiling.rst
--- ns-3.41/doc/manual/source/profiling.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/profiling.rst	2024-05-29 15:29:46.876073000 -0700
@@ -636,6 +636,24 @@
     and inlining TtlExceeded. This resulted in a ~1.02x speedup with the test suite (``./test.py -d``).
     More details on: merge requests `MR681`_ and `MR685`_.
 
+Perf on WSL
+~~~~~~~~~~~
+
+WSLv1 cannot use perf due to the lack of the linux kernel and its performance counters.
+
+WSLv2 users need to manually build perf to profile their programs,
+which can be accomplished with the following commands:
+
+.. sourcecode:: console
+
+    apt install flex bison
+    git clone https://github.com/microsoft/WSL2-Linux-Kernel --depth 1
+    cd WSL2-Linux-Kernel/tools/perf
+    make -j8
+    sudo cp perf /usr/local/bin
+
+Note that hardware `performance counters <https://github.com/microsoft/WSL/issues/4678>`_
+are only available in Windows 11.
 
 AMD uProf
 +++++++++
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/python.rst ns-3.42/doc/manual/source/python.rst
--- ns-3.41/doc/manual/source/python.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/python.rst	2024-05-29 15:29:46.876073000 -0700
@@ -52,45 +52,45 @@
 
   from ns import ns
 
-  ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
-  ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
+  ns.LogComponentEnable("UdpEchoClientApplication", ns.LOG_LEVEL_INFO)
+  ns.LogComponentEnable("UdpEchoServerApplication", ns.LOG_LEVEL_INFO)
 
-  nodes = ns.network.NodeContainer()
+  nodes = ns.NodeContainer()
   nodes.Create(2)
 
-  pointToPoint = ns.point_to_point.PointToPointHelper()
-  pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
-  pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
+  pointToPoint = ns.PointToPointHelper()
+  pointToPoint.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
+  pointToPoint.SetChannelAttribute("Delay", ns.StringValue("2ms"))
 
   devices = pointToPoint.Install(nodes)
 
-  stack = ns.internet.InternetStackHelper()
+  stack = ns.InternetStackHelper()
   stack.Install(nodes)
 
-  address = ns.internet.Ipv4AddressHelper()
-  address.SetBase(ns.network.Ipv4Address("10.1.1.0"),
-                  ns.network.Ipv4Mask("255.255.255.0"))
+  address = ns.Ipv4AddressHelper()
+  address.SetBase(ns.Ipv4Address("10.1.1.0"),
+                  ns.Ipv4Mask("255.255.255.0"))
 
   interfaces = address.Assign(devices)
 
-  echoServer = ns.applications.UdpEchoServerHelper(9)
+  echoServer = ns.UdpEchoServerHelper(9)
 
   serverApps = echoServer.Install(nodes.Get(1))
-  serverApps.Start(ns.core.Seconds(1.0))
-  serverApps.Stop(ns.core.Seconds(10.0))
+  serverApps.Start(ns.Seconds(1.0))
+  serverApps.Stop(ns.Seconds(10.0))
 
   address = interfaces.GetAddress(1).ConvertTo()
-  echoClient = ns.applications.UdpEchoClientHelper(address, 9)
-  echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
-  echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
-  echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
+  echoClient = ns.UdpEchoClientHelper(address, 9)
+  echoClient.SetAttribute("MaxPackets", ns.UintegerValue(1))
+  echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
+  echoClient.SetAttribute("PacketSize", ns.UintegerValue(1024))
 
   clientApps = echoClient.Install(nodes.Get(0))
-  clientApps.Start(ns.core.Seconds(2.0))
-  clientApps.Stop(ns.core.Seconds(10.0))
+  clientApps.Start(ns.Seconds(2.0))
+  clientApps.Stop(ns.Seconds(10.0))
 
-  ns.core.Simulator.Run()
-  ns.core.Simulator.Destroy()
+  ns.Simulator.Run()
+  ns.Simulator.Destroy()
 
 
 
@@ -111,11 +111,11 @@
 Using the bindings from the ns-3 source
 =======================================
 
-The main prerequisite is to install `cppyy`, with version no later than 2.4.2.
+The main prerequisite is to install `cppyy`, with version 3.1.2.
 Depending on how you may manage
 Python extensions, the installation instructions may vary, but you can first
 check if it installed by seeing if the `cppyy` module can be
-successfully imported and the version is no later than 2.4.2:
+successfully imported and the version 3.1.2:
 
 .. sourcecode:: bash
 
@@ -125,7 +125,7 @@
   Type "help", "copyright", "credits" or "license" for more information.
   >>> import cppyy
   >>> print("%s" % cppyy.__version)
-  2.4.2
+  3.1.2
   >>>
 
 If not, you may try to install via `pip` or whatever other manager you are
@@ -133,7 +133,7 @@
 
 .. sourcecode:: bash
 
-  $ python3 -m pip install --user cppyy==2.4.2
+  $ python3 -m pip install --user cppyy==3.1.2
 
 First, we need to enable the build of Python bindings:
 
@@ -226,71 +226,71 @@
 
 ::
 
-    from ns import ns
+  from ns import ns
 
-    ns.cppyy.cppdef("""
-            using namespace ns3;
+  ns.cppyy.cppdef("""
+              using namespace ns3;
 
-            Callback<void,Ptr<const Packet>,const Address&,const Address&>
-            make_sinktrace_callback(void(*func)(Ptr<Packet>,Address,Address))
-            {
-                return MakeCallback(func);
-            }
-        """)
-
-    # Define the trace callback
-    def SinkTracer(packet: ns.Packet, src_address: ns.Address, dst_address: ns.Address) -> None:
-        print(f"At {ns.Simulator.Now().GetSeconds():.0f}s, '{dst_address}' received packet"
-              f" with {packet.__deref__().GetSerializedSize()} bytes from '{src_address}'")
-
-    # Create two nodes
-    csmaNodes = ns.network.NodeContainer()
-    csmaNodes.Create(2)
-
-    # Connect the two nodes
-    csma = ns.csma.CsmaHelper()
-    csma.SetChannelAttribute("DataRate", ns.core.StringValue("100Mbps"))
-    csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.NanoSeconds(6560)))
-    csmaDevices = csma.Install(csmaNodes)
-
-    # Install the internet stack
-    stack = ns.internet.InternetStackHelper()
-    stack.Install(csmaNodes)
-
-    # Assign Ipv4 addresses
-    address = ns.internet.Ipv4AddressHelper()
-    address.SetBase(ns.network.Ipv4Address("10.1.2.0"), ns.network.Ipv4Mask("255.255.255.0"))
-    csmaInterfaces = address.Assign(csmaDevices)
-
-    # Setup applications
-    echoServer = ns.applications.UdpEchoServerHelper(9)
-
-    serverApps = echoServer.Install(csmaNodes.Get(0))
-    serverApps.Start(ns.core.Seconds(1.0))
-    serverApps.Stop(ns.core.Seconds(10.0))
-
-    echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(0).ConvertTo(), 9)
-    echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(10))
-    echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
-    echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
-
-    clientApps = echoClient.Install(csmaNodes.Get(1))
-    clientApps.Start(ns.core.Seconds(2.0))
-    clientApps.Stop(ns.core.Seconds(10.0))
-
-    # Populate routing tables
-    ns.internet.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
-
-    # Setup the trace callback
-    sinkTraceCallback = ns.cppyy.gbl.make_sinktrace_callback(SinkTracer)
-    serverApps.Get(0).__deref__().TraceConnectWithoutContext("RxWithAddresses", sinkTraceCallback);
-
-    # Set the simulation duration to 11 seconds
-    ns.Simulator.Stop(ns.Seconds(11))
-
-    # Run the simulator
-    ns.Simulator.Run()
-    ns.Simulator.Destroy()
+              Callback<void,Ptr<const Packet>,const Address&,const Address&>
+              make_sinktrace_callback(void(*func)(Ptr<const Packet>, const Address&,const Address&))
+              {
+                  return MakeCallback(func);
+              }
+          """)
+
+  # Define the trace callback
+  def SinkTracer(packet: ns.Packet, src_address: ns.Address, dst_address: ns.Address) -> None:
+      print(f"At {ns.Simulator.Now().GetSeconds():.0f}s, '{dst_address}' received packet"
+            f" with {packet.__deref__().GetSerializedSize()} bytes from '{src_address}'")
+
+  # Create two nodes
+  csmaNodes = ns.NodeContainer()
+  csmaNodes.Create(2)
+
+  # Connect the two nodes
+  csma = ns.CsmaHelper()
+  csma.SetChannelAttribute("DataRate", ns.StringValue("100Mbps"))
+  csma.SetChannelAttribute("Delay", ns.TimeValue(ns.NanoSeconds(6560)))
+  csmaDevices = csma.Install(csmaNodes)
+
+  # Install the internet stack
+  stack = ns.InternetStackHelper()
+  stack.Install(csmaNodes)
+
+  # Assign Ipv4 addresses
+  address = ns.Ipv4AddressHelper()
+  address.SetBase(ns.Ipv4Address("10.1.2.0"), ns.Ipv4Mask("255.255.255.0"))
+  csmaInterfaces = address.Assign(csmaDevices)
+
+  # Setup applications
+  echoServer = ns.UdpEchoServerHelper(9)
+
+  serverApps = echoServer.Install(csmaNodes.Get(0))
+  serverApps.Start(ns.Seconds(1.0))
+  serverApps.Stop(ns.Seconds(10.0))
+
+  echoClient = ns.UdpEchoClientHelper(csmaInterfaces.GetAddress(0).ConvertTo(), 9)
+  echoClient.SetAttribute("MaxPackets", ns.UintegerValue(10))
+  echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
+  echoClient.SetAttribute("PacketSize", ns.UintegerValue(1024))
+
+  clientApps = echoClient.Install(csmaNodes.Get(1))
+  clientApps.Start(ns.Seconds(2.0))
+  clientApps.Stop(ns.Seconds(10.0))
+
+  # Populate routing tables
+  ns.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
+
+  # Setup the trace callback
+  sinkTraceCallback = ns.cppyy.gbl.make_sinktrace_callback(SinkTracer)
+  serverApps.Get(0).__deref__().TraceConnectWithoutContext("RxWithAddresses", sinkTraceCallback);
+
+  # Set the simulation duration to 11 seconds
+  ns.Simulator.Stop(ns.Seconds(11))
+
+  # Run the simulator
+  ns.Simulator.Run()
+  ns.Simulator.Destroy()
 
 Which should print:
 
@@ -326,31 +326,32 @@
 
 .. sourcecode:: python
 
-    # Import the ns-3 C++ modules with Cppyy
-    from ns import ns
+  # Import the ns-3 C++ modules with Cppyy
+  from ns import ns
+  import sys
 
-    # To pass the addresses of the Python variables to c++, we need to use ctypes
-    from ctypes import c_bool, c_int, c_double, c_char_p, create_string_buffer
-    verbose = c_bool(True)
-    nCsma = c_int(3)
-    throughputKbps = c_double(3.1415)
-    BUFFLEN = 4096
-    outputFileBuffer = create_string_buffer(b"default_output_file.xml", BUFFLEN)
-    outputFile = c_char_p(outputFileBuffer.raw)
-
-    # Cppyy will transform the ctype types into the appropriate reference or raw pointers
-    cmd = ns.CommandLine(__file__)
-    cmd.AddValue("verbose", "Tell echo applications to log if true", verbose)
-    cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma)
-    cmd.AddValue("throughputKbps", "Throughput of nodes", throughputKbps)
-    cmd.AddValue("outputFile", "Output file name", outputFile, BUFFLEN)
-    cmd.Parse(sys.argv)
-
-    # Printing values of the different ctypes passed as arguments post parsing
-    print("Verbose:", verbose.value)
-    print("nCsma:", nCsma.value)
-    print("throughputKbps:", throughputKbps.value)
-    print("outputFile:", outputFile.value)
+  # To pass the addresses of the Python variables to c++, we need to use ctypes
+  from ctypes import c_bool, c_int, c_double, c_char_p, create_string_buffer
+  verbose = c_bool(True)
+  nCsma = c_int(3)
+  throughputKbps = c_double(3.1415)
+  BUFFLEN = 4096
+  outputFileBuffer = create_string_buffer(b"default_output_file.xml", BUFFLEN)
+  outputFile = c_char_p(outputFileBuffer.raw)
+
+  # Cppyy will transform the ctype types into the appropriate reference or raw pointers
+  cmd = ns.CommandLine(__file__)
+  cmd.AddValue("verbose", "Tell echo applications to log if true", verbose)
+  cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma)
+  cmd.AddValue("throughputKbps", "Throughput of nodes", throughputKbps)
+  cmd.AddValue("outputFile", "Output file name", outputFile, BUFFLEN)
+  cmd.Parse(sys.argv)
+
+  # Printing values of the different ctypes passed as arguments post parsing
+  print("Verbose:", verbose.value)
+  print("nCsma:", nCsma.value)
+  print("throughputKbps:", throughputKbps.value)
+  print("outputFile:", outputFile.value)
 
 Note that the variables are passed as references or raw pointers. Reassigning them on the Python side
 (e.g. ``verbose = verbose.value``) can result in the Python garbage collector destroying the object
@@ -371,62 +372,63 @@
 
 .. sourcecode:: python
 
-    from ns import ns
-    from ctypes import c_char_p, c_char, create_string_buffer, byref, cast
+  from ns import ns
+  from ctypes import c_char_p, c_char, create_string_buffer, byref, cast
 
-    # The following buffer represent the memory contents
-    # of a program containing two adjacent C strings
-    # This could be the result of two subsequent variables
-    # on the stack or dynamically allocated
-    memoryContents = create_string_buffer(b"SHORT_STRING_CONTENTS\0"+b"DoNotWriteHere_"*5+b"\0")
-    lenShortString = len(b"SHORT_STRING_CONTENTS\0")
-
-    # In the next lines, we pick pointers to these two C strings
-    shortStringBuffer = cast(byref(memoryContents, 0), c_char_p)
-    victimBuffer = cast(byref(memoryContents, lenShortString), c_char_p)
-
-    cmd = ns.core.CommandLine(__file__)
-    # in the real implementation, the buffer size of 21+1 bytes containing SHORT_STRING_CONTENTS\0 is passed
-    cmd.AddValue("shortString", "", shortStringBuffer)
-
-    print("Memory contents before the memory corruption")
-    print("Full Memory contents", memoryContents.raw)
-    print("shortStringBuffer contents: ", shortStringBuffer.value)
-    print("victimBuffer contents: ", victimBuffer.value)
-
-    # The following block should print to the terminal.
-    # Note that the strings are correctly
-    # identified due to the null terminator (\x00)
-    #
-    # Memory contents before the memory corruption
-    # Full Memory contents b'SHORT_STRING_CONTENTS\x00DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00'
-    # shortStringBuffer size=21, contents: b'SHORT_STRING_CONTENTS'
-    # victimBuffer size=75, contents: b'DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_'
-
-    # Write a very long string to a small buffer of size lenShortString = 22
-    cmd.Parse(["python", "--shortString="+("OkToWrite"*lenShortString)[:lenShortString]+"CORRUPTED_"*3])
-
-    print("\n\nMemory contents after the memory corruption")
-    print("Full Memory contents", memoryContents.raw)
-    print("shortStringBuffer contents: ", shortStringBuffer.value)
-    print("victimBuffer contents: ", victimBuffer.value)
-
-    # The following block should print to the terminal.
-    #
-    # Memory contents after the memory corruption
-    # Full Memory contents b'OkToWriteOkToWriteOkToCORRUPTED_CORRUPTED_CORRUPTED_\x00oNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00'
-    # shortStringBuffer size=52, contents: b'OkToWriteOkToWriteOkToCORRUPTED_CORRUPTED_CORRUPTED_'
-    # victimBuffer size=30, contents: b'CORRUPTED_CORRUPTED_CORRUPTED_'
-    #
-    # Note that shortStringBuffer invaded the victimBuffer since the
-    # string being written was bigger than the shortStringBuffer.
-    #
-    # Since no bounds checks were performed, the adjacent memory got
-    # overwritten and both buffers are now corrupted.
-    #
-    # We also have a memory leak of the final block in the memory
-    # 'oNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00', caused
-    # by the null terminator written at the middle of the victimBuffer.
+  # The following buffer represent the memory contents
+  # of a program containing two adjacent C strings
+  # This could be the result of two subsequent variables
+  # on the stack or dynamically allocated
+  memoryContents = create_string_buffer(b"SHORT_STRING_CONTENTS\0"+b"DoNotWriteHere_"*5+b"\0")
+  lenShortString = len(b"SHORT_STRING_CONTENTS\0")
+
+  # In the next lines, we pick pointers to these two C strings
+  shortStringBuffer = cast(byref(memoryContents, 0), c_char_p)
+  victimBuffer = cast(byref(memoryContents, lenShortString), c_char_p)
+
+  cmd = ns.CommandLine(__file__)
+  # in the real implementation, the buffer size of 21+1 bytes containing SHORT_STRING_CONTENTS\0 is passed
+  # we use the entire size of the memory contents for demonstration purposses
+  cmd.AddValue("shortString", "", shortStringBuffer, 75)
+
+  print("Memory contents before the memory corruption")
+  print("Full Memory contents", memoryContents.raw)
+  print("shortStringBuffer contents: ", shortStringBuffer.value)
+  print("victimBuffer contents: ", victimBuffer.value)
+
+  # The following block should print to the terminal.
+  # Note that the strings are correctly
+  # identified due to the null terminator (\x00)
+  #
+  # Memory contents before the memory corruption
+  # Full Memory contents b'SHORT_STRING_CONTENTS\x00DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00'
+  # shortStringBuffer size=21, contents: b'SHORT_STRING_CONTENTS'
+  # victimBuffer size=75, contents: b'DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_DoNotWriteHere_'
+
+  # Write a very long string to a small buffer of size lenShortString = 22
+  cmd.Parse(["python", "--shortString="+("OkToWrite"*lenShortString)[:lenShortString]+"CORRUPTED_"*3])
+
+  print("\n\nMemory contents after the memory corruption")
+  print("Full Memory contents", memoryContents.raw)
+  print("shortStringBuffer contents: ", shortStringBuffer.value)
+  print("victimBuffer contents: ", victimBuffer.value)
+
+  # The following block should print to the terminal.
+  #
+  # Memory contents after the memory corruption
+  # Full Memory contents b'OkToWriteOkToWriteOkToCORRUPTED_CORRUPTED_CORRUPTED_\x00oNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00'
+  # shortStringBuffer size=52, contents: b'OkToWriteOkToWriteOkToCORRUPTED_CORRUPTED_CORRUPTED_'
+  # victimBuffer size=30, contents: b'CORRUPTED_CORRUPTED_CORRUPTED_'
+  #
+  # Note that shortStringBuffer invaded the victimBuffer since the
+  # string being written was bigger than the shortStringBuffer.
+  #
+  # Since no bounds checks were performed, the adjacent memory got
+  # overwritten and both buffers are now corrupted.
+  #
+  # We also have a memory leak of the final block in the memory
+  # 'oNotWriteHere_DoNotWriteHere_DoNotWriteHere_\x00\x00', caused
+  # by the null terminator written at the middle of the victimBuffer.
 
 If you find a segmentation violation, be sure to wait for the stacktrace provided by Cppyy
 and try to find the root cause of the issue. If you have multiple cores, the number of
@@ -443,22 +445,22 @@
 
 .. sourcecode:: python
 
-    # Redefine Time operators
-    cppyy.cppdef("""
-        using namespace ns3;
-        bool Time_ge(Time& a, Time& b){ return a >= b;}
-        bool Time_eq(Time& a, Time& b){ return a == b;}
-        bool Time_ne(Time& a, Time& b){ return a != b;}
-        bool Time_le(Time& a, Time& b){ return a <= b;}
-        bool Time_gt(Time& a, Time& b){ return a > b;}
-        bool Time_lt(Time& a, Time& b){ return a < b;}
-    """)
-    cppyy.gbl.ns3.Time.__ge__ = cppyy.gbl.Time_ge
-    cppyy.gbl.ns3.Time.__eq__ = cppyy.gbl.Time_eq
-    cppyy.gbl.ns3.Time.__ne__ = cppyy.gbl.Time_ne
-    cppyy.gbl.ns3.Time.__le__ = cppyy.gbl.Time_le
-    cppyy.gbl.ns3.Time.__gt__ = cppyy.gbl.Time_gt
-    cppyy.gbl.ns3.Time.__lt__ = cppyy.gbl.Time_lt
+  # Redefine Time operators
+  cppyy.cppdef("""
+      using namespace ns3;
+      bool Time_ge(Time& a, Time& b){ return a >= b;}
+      bool Time_eq(Time& a, Time& b){ return a == b;}
+      bool Time_ne(Time& a, Time& b){ return a != b;}
+      bool Time_le(Time& a, Time& b){ return a <= b;}
+      bool Time_gt(Time& a, Time& b){ return a > b;}
+      bool Time_lt(Time& a, Time& b){ return a < b;}
+  """)
+  cppyy.gbl.ns3.Time.__ge__ = cppyy.gbl.Time_ge
+  cppyy.gbl.ns3.Time.__eq__ = cppyy.gbl.Time_eq
+  cppyy.gbl.ns3.Time.__ne__ = cppyy.gbl.Time_ne
+  cppyy.gbl.ns3.Time.__le__ = cppyy.gbl.Time_le
+  cppyy.gbl.ns3.Time.__gt__ = cppyy.gbl.Time_gt
+  cppyy.gbl.ns3.Time.__lt__ = cppyy.gbl.Time_lt
 
 
 A different operator used by |ns3| is `operator Address()`, used to
@@ -467,8 +469,8 @@
 
 .. sourcecode:: python
 
-    # Explicitly convert the InetSocketAddress to Address using InetSocketAddress.ConvertTo()
-    sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80).ConvertTo())
+  # Explicitly convert the InetSocketAddress to Address using InetSocketAddress.ConvertTo()
+  sink.Bind(ns.InetSocketAddress(ns.Ipv4Address.GetAny(), 80).ConvertTo())
 
 Most of the missing APIs can be wrapped, given enough time, patience, and expertise, and will likely be wrapped if bug reports are submitted.
 However, don't file a bug report saying "bindings are incomplete", because the project does not have maintainers to maintain every API.
@@ -487,11 +489,11 @@
 
 ::
 
-    ascii = ns.ofstream("wifi-ap.tr") # create the file
-    ns.YansWifiPhyHelper.EnableAsciiAll(ascii)
-    ns.Simulator.Run()
-    ns.Simulator.Destroy()
-    ascii.close() # close the file
+  ascii = ns.ofstream("wifi-ap.tr") # create the file
+  ns.YansWifiPhyHelper.EnableAsciiAll(ascii)
+  ns.Simulator.Run()
+  ns.Simulator.Destroy()
+  ascii.close() # close the file
 
 There is one caveat: you must not allow the file object to be garbage collected while |ns3| is still using it.
 That means that the 'ascii' variable above must not be allowed to go out of scope or else the program will crash.
@@ -507,14 +509,14 @@
 ::
 
   from ns import ns
-  n1 = ns.network.Node()
+  n1 = ns.Node()
 
 or
 
 ::
 
   from ns import*
-  n1 = ns.network.Node()
+  n1 = ns.Node()
 
 The best way to explore the bindings is to look at the various example
 programs provided in |ns3|; some C++ examples have a corresponding Python
@@ -616,23 +618,23 @@
 
 .. sourcecode:: yaml
 
-      # Install minimal toolchain
-      - yum install -y libxml2-devel gsl-devel sqlite-devel gtk3-devel boost-devel
-      # Create Python venv
-      - $PYTHON -m venv ./venv
-      - . ./venv/bin/activate
-      # Upgrade the pip version to reuse the pre-build cppyy
-      - $PYTHON -m pip install pip --upgrade
-      - $PYTHON -m pip install setuptools setuptools_scm --upgrade
-      - $PYTHON -m pip install wheel auditwheel cmake-build-extension cppyy
+  # Install minimal toolchain
+  - yum install -y libxml2-devel gsl-devel sqlite-devel gtk3-devel boost-devel
+  # Create Python venv
+  - $PYTHON -m venv ./venv
+  - . ./venv/bin/activate
+  # Upgrade the pip version to reuse the pre-build cppyy
+  - $PYTHON -m pip install pip --upgrade
+  - $PYTHON -m pip install setuptools setuptools_scm --upgrade
+  - $PYTHON -m pip install wheel auditwheel cmake-build-extension cppyy
 
 The project is then configured loading the configuration settings defined
 in the ``ns-3-dev/setup.py`` file.
 
 .. sourcecode:: yaml
 
-      # Configure and build wheel
-      - $PYTHON setup.py bdist_wheel build_ext
+  # Configure and build wheel
+  - $PYTHON setup.py bdist_wheel build_ext
 
 At this point, we have a wheel that only works in the current system,
 since external libraries are not shipped.
@@ -645,9 +647,9 @@
 
 .. sourcecode:: yaml
 
-      - export EXCLUDE_INTERNAL_LIBRARIES=`$PYTHON ./build-support/pip-wheel/auditwheel-exclude-list.py`
-      # Bundle in shared libraries that were not explicitly packaged or depended upon
-      - $PYTHON -m auditwheel repair ./dist/*whl -L /lib64 $EXCLUDE_INTERNAL_LIBRARIES
+  - export EXCLUDE_INTERNAL_LIBRARIES=`$PYTHON ./build-support/pip-wheel/auditwheel-exclude-list.py`
+  # Bundle in shared libraries that were not explicitly packaged or depended upon
+  - $PYTHON -m auditwheel repair ./dist/*whl -L /lib64 $EXCLUDE_INTERNAL_LIBRARIES
 
 
 At this point, we should have our final wheel ready, but we need to check if it works
@@ -657,48 +659,48 @@
 
 .. sourcecode:: yaml
 
-      # Clean the build directory
-      - $PYTHON ./ns3 clean
-      # Clean up the environment
-      - deactivate
-      - rm -R ./venv
-      # Delete toolchain to check if required headers/libraries were really packaged
-      - yum remove -y libxml2-devel gsl-devel sqlite-devel gtk3-devel boost-devel
+  # Clean the build directory
+  - $PYTHON ./ns3 clean
+  # Clean up the environment
+  - deactivate
+  - rm -R ./venv
+  # Delete toolchain to check if required headers/libraries were really packaged
+  - yum remove -y libxml2-devel gsl-devel sqlite-devel gtk3-devel boost-devel
 
 
 Then we can install our newly built wheel and test it.
 
 .. sourcecode:: yaml
 
-      # Install wheel
-      - $PYTHON -m pip install ./wheelhouse/*whl
-      - $PYTHON -m pip install matplotlib numpy
-      # Test the bindings
-      - $PYTHON ./utils/python-unit-tests.py
-      - $PYTHON ./examples/realtime/realtime-udp-echo.py
-      - $PYTHON ./examples/routing/simple-routing-ping6.py
-      - $PYTHON ./examples/tutorial/first.py
-      - $PYTHON ./examples/tutorial/second.py
-      - $PYTHON ./examples/tutorial/third.py
-      - $PYTHON ./examples/wireless/wifi-ap.py
-      - $PYTHON ./examples/wireless/mixed-wired-wireless.py
-      - $PYTHON ./src/bridge/examples/csma-bridge.py
-      - $PYTHON ./src/brite/examples/brite-generic-example.py
-      - $PYTHON ./src/core/examples/sample-simulator.py
-      - $PYTHON ./src/core/examples/sample-rng-plot.py --not-blocking
-      - $PYTHON ./src/click/examples/nsclick-simple-lan.py
-      - $PYTHON ./src/flow-monitor/examples/wifi-olsr-flowmon.py
-      - $PYTHON ./src/flow-monitor/examples/flowmon-parse-results.py output.xml
-      - $PYTHON ./src/openflow/examples/openflow-switch.py
+  # Install wheel
+  - $PYTHON -m pip install ./wheelhouse/*whl
+  - $PYTHON -m pip install matplotlib numpy
+  # Test the bindings
+  - $PYTHON ./utils/python-unit-tests.py
+  - $PYTHON ./examples/realtime/realtime-udp-echo.py
+  - $PYTHON ./examples/routing/simple-routing-ping6.py
+  - $PYTHON ./examples/tutorial/first.py
+  - $PYTHON ./examples/tutorial/second.py
+  - $PYTHON ./examples/tutorial/third.py
+  - $PYTHON ./examples/wireless/wifi-ap.py
+  - $PYTHON ./examples/wireless/mixed-wired-wireless.py
+  - $PYTHON ./src/bridge/examples/csma-bridge.py
+  - $PYTHON ./src/brite/examples/brite-generic-example.py
+  - $PYTHON ./src/core/examples/sample-simulator.py
+  - $PYTHON ./src/core/examples/sample-rng-plot.py --not-blocking
+  - $PYTHON ./src/click/examples/nsclick-simple-lan.py
+  - $PYTHON ./src/flow-monitor/examples/wifi-olsr-flowmon.py
+  - $PYTHON ./src/flow-monitor/examples/flowmon-parse-results.py output.xml
+  - $PYTHON ./src/openflow/examples/openflow-switch.py
 
 If all programs finish normally, the bindings are working as expected,
 and will be saved as an artifact.
 
 .. sourcecode:: yaml
 
-    artifacts:
-      paths:
-        - wheelhouse/*.whl
+  artifacts:
+    paths:
+      - wheelhouse/*.whl
 
 One can use ``gitlab-ci-local`` to build the pip wheels locally. After that, the wheels
 will be stored in ``.gitlab-ci-local/artifacts/manylinux-pip-wheel-py3Lg10/wheelhouse``
@@ -730,7 +732,7 @@
 
 .. sourcecode:: bash
 
-    $ pip install *.whl
+  $ pip install *.whl
 
 Publishing the pip wheel via Pypi
 *********************************
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/test-framework.rst ns-3.42/doc/manual/source/test-framework.rst
--- ns-3.41/doc/manual/source/test-framework.rst	2024-02-09 14:44:07.777789000 -0800
+++ ns-3.42/doc/manual/source/test-framework.rst	2024-05-29 15:29:46.876073000 -0700
@@ -761,9 +761,9 @@
   };
 
   MyTestSuite::MyTestSuite()
-    : TestSuite("my-test-suite-name", UNIT)
+    : TestSuite("my-test-suite-name", Type::UNIT)
   {
-    AddTestCase(new MyTestCase, TestCase::QUICK);
+    AddTestCase(new MyTestCase, TestCase::Duration::QUICK);
   }
 
   static MyTestSuite myTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/working-with-cmake.rst ns-3.42/doc/manual/source/working-with-cmake.rst
--- ns-3.41/doc/manual/source/working-with-cmake.rst	2024-02-09 14:44:07.781789300 -0800
+++ ns-3.42/doc/manual/source/working-with-cmake.rst	2024-05-29 15:29:46.876073000 -0700
@@ -173,7 +173,7 @@
 +=========================+========================+===============================+=================================+
 | debug                   | debug                  |                               | -g                              |
 +-------------------------+------------------------+-------------------------------+---------------------------------+
-| default                 | default                |                               | -O2 -g                          |
+| default                 | default                |                               | -Os -g                          |
 +-------------------------+------------------------+-------------------------------+---------------------------------+
 | release                 | release                |                               | -O3                             |
 +-------------------------+------------------------+-------------------------------+---------------------------------+
@@ -235,9 +235,9 @@
 +==================+===================+
 | DEBUG            | -g                |
 +------------------+-------------------+
-| DEFAULT          | -O2 -g -DNDEBUG   |
+| DEFAULT          | -Os -g -DNDEBUG   |
 +------------------+-------------------+
-| RELWITHDEBINFO   | -O2 -g -DNDEBUG   |
+| RELWITHDEBINFO   | -Os -g -DNDEBUG   |
 +------------------+-------------------+
 | RELEASE          | -O3 -DNDEBUG      |
 +------------------+-------------------+
@@ -1965,7 +1965,7 @@
   --
   -- Copying /ns-3-dev/cmake-build-release/_deps/armadillo-src/include/ to /ns-3-dev/cmake-build-release/_deps/armadillo-build/tmp/include/
   -- Generating /ns-3-dev/cmake-build-release/_deps/armadillo-build/tmp/include/config.hpp
-  -- CMAKE_CXX_FLAGS           =  -fsanitize=address,leak,undefined -O2
+  -- CMAKE_CXX_FLAGS           =  -fsanitize=address,leak,undefined -Os
   -- CMAKE_SHARED_LINKER_FLAGS =  -Wl,--no-as-needed
   -- CMAKE_REQUIRED_INCLUDES   = /usr/include;/usr/include/superlu
   --
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/working-with-docker.rst ns-3.42/doc/manual/source/working-with-docker.rst
--- ns-3.41/doc/manual/source/working-with-docker.rst	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/doc/manual/source/working-with-docker.rst	2024-05-29 15:29:46.876073000 -0700
@@ -0,0 +1,585 @@
+.. include:: replace.txt
+.. highlight:: bash
+
+
+.. _Docker : https://docs.docker.com/desktop/
+.. _rootless mode : https://docs.docker.com/engine/security/rootless/
+.. _Podman : https://podman.io/
+.. _Apptainer : https://apptainer.org/docs/user/latest/
+.. _continuous integration (CI) : https://docs.gitlab.com/ee/ci/
+
+.. _Working with Docker:
+
+Working with Docker
+-------------------
+
+The ns-3 project repository is currently hosted in GitLab, which includes
+`continuous integration (CI)`_ tools to automate build, tests, packaging and
+distribution of software. The CI works based on jobs, that are defined
+in YAML files, which specify a container the job will run on.
+
+See :ref:`Working with gitlab-ci-local<Working with gitlab-ci-local>` for how
+to use containers for running our CI checks locally.
+
+A container is a lightweight virtualization tool that allows one to use user space
+tools from different OSes on top of the same kernel. This drastically cuts the
+overhead of alternatives such as full virtualization, where a complete operating
+system and the hardware it runs on needs to be emulated, or the hardware switched
+between a host and a guest OS via a hypervisor.
+
+The most common type of containers are applications containers, where
+:ref:`Docker <Docker containers>` is the most popular solution.
+
+.. _Docker pricing: https://www.docker.com/pricing/
+
+Note on pricing: notice that commercial and governmental use of Docker
+may require a subscription. See `Docker pricing`_ for more information.
+:ref:`Podman <Podman containers>` is an open-source drop-in replacement.
+
+Note on security: Docker is installed by default with root privileges.
+This is a security hazard if you are running untrusted software,
+especially in shared environments. Docker can be installed in
+`rootless mode`_ for better isolation, however, the alternatives such
+as `Podman`_ and `Apptainer`_ (previously Singularity) provide safer
+default settings. You can read more on `Docker security`_.
+
+.. _Docker containers:
+
+Docker containers
+*****************
+
+`Docker`_ popularized containers and made them ubiquitous in continuous integration
+due to its ease of use. This section will consolidate the basics of how to work
+with Docker or its compatible alternatives.
+
+.. _Docker security: https://docs.docker.com/engine/security/
+
+Docker workflow typically consists of 10 steps:
+
+#. `Install Docker`_
+#. `Write a Dockerfile`_
+#. `Build a Docker container image`_
+#. `Create a container based on the image`_
+#. `Start the container`_
+#. `Access the container`_
+#. `Stop the container`_
+#. `Deleting the container`_
+#. `Publishing the container image`_
+#. `Deleting the container image`_
+
+.. _Install Docker:
+
+Install Docker
+==============
+
+Docker is usually set up (*e.g.* via system package managers or their official
+installers) in root mode, requiring frequent use of administrative
+permissions/sudo, which is necessary for some services, but not for most.
+For proper isolation, install Docker in `rootless mode`_, or use one of
+its compatible alternatives.
+
+.. _Write a Dockerfile:
+
+Write a Dockerfile
+==================
+
+.. _special keywords: https://docs.docker.com/engine/reference/builder/
+
+A Dockerfile is a file that contains instructions of how to build an image of the
+container that will host the application / service. These files are composed of
+one-line commands using `special keywords`_. The most common keywords are:
+
+* ``FROM``: used to specify a parent image
+* ``COPY``: used to copy files from the external build directory into the container
+* ``RUN``: run shell commands to install dependencies and set up the service
+* ``ENTRYPOINT``: program to be started when the container is launched
+
+Here is one example of a ``Dockerfile`` that can be used to debug a ns-3
+program on Fedora 37:
+
+.. sourcecode:: docker
+
+    FROM fedora:37
+
+    RUN dnf update --assumeyes && dnf install --assumeyes gcc-c++ cmake ccache ninja-build python gdb
+
+    ENTRYPOINT ["bash"]
+
+When Docker is called to build the container image for this Dockerfile, it will
+pull the image for fedora:37 from a ``Docker Registry``. Common registries
+include docker.io (which hosts images shown in the DockerHub webpage), quay.io,
+GitHub, GitLab, or you can have your own self-hosted option.
+
+Note: For security reasons, it is not recommended to run third-party images
+in production. Dockerfiles are embedded into docker images and can be checked.
+One example of how this can be done is shown below:
+
+.. sourcecode:: console
+
+    $ docker image ls
+    REPOSITORY                    TAG         IMAGE ID      CREATED       SIZE
+    fedoradebugging               37          d96491e23a80  10 days ago   829 MB
+
+    $ docker history fedoradebugging
+    ID            CREATED       CREATED BY                                     SIZE        COMMENT
+    0b56b184852b  10 days ago   /bin/sh -c #(nop) ENTRYPOINT ["bash"]          0 B
+    <missing>     10 days ago   /bin/sh -c dnf update --assumeyes && dnf i...  648 MB      FROM registry.fedoraproject.org/fedora:37
+    4105b568d464  2 months ago                                                 182 MB      Created by Image Factory
+
+We can see different ``layers`` (commands) that compose the final docker image.
+When compared to the Dockerfile, they show up in reverse order from the latest
+to the earliest event.
+
+.. _Build a Docker container image:
+
+Build a Docker container image
+==============================
+
+When building toolchain containers to work on projects, we typically don't
+want to copy the projects themselves into the container. So we need to pass
+an empty directory to Docker.
+
+We also need to specify a tag for our image, otherwise it will have a randomly
+assigned name which we will have to refer to later.
+
+.. sourcecode:: console
+
+    $ mkdir empty-dir
+
+    $ docker image ls
+    REPOSITORY                         TAG         IMAGE ID      CREATED             SIZE
+
+    $ docker build -t fedoradebugging:37 -f Dockerfile ./empty-dir
+    STEP 1/3: FROM fedora:37
+    Resolved "fedora" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
+    Trying to pull registry.fedoraproject.org/fedora:37...
+    Getting image source signatures
+    Copying blob 80b613d8f1ff done
+    Copying config 4105b568d4 done
+    Writing manifest to image destination
+    Storing signatures
+    STEP 2/3: RUN dnf update --assumeyes && dnf install --assumeyes gcc-c++ cmake ccache ninja-build python gdb
+    Fedora 37 - x86_64                              4.0 MB/s |  82 MB     00:20
+    Fedora 37 openh264 (From Cisco) - x86_64        2.1 kB/s | 2.5 kB     00:01
+    Fedora Modular 37 - x86_64                      1.6 MB/s | 3.8 MB     00:02
+    Fedora 37 - x86_64 - Updates                    5.0 MB/s |  41 MB     00:08
+    Fedora Modular 37 - x86_64 - Updates            1.3 MB/s | 2.9 MB     00:02
+    Last metadata expiration check: 0:00:01 ago on Fri Feb  2 13:41:30 2024.
+    Dependencies resolved.
+    ================================================================================
+     Package                         Arch       Version           Repository   Size
+    ================================================================================
+    Upgrading:
+     elfutils-default-yama-scope     noarch     0.190-2.fc37      updates      12 k
+     ...
+    (38/56): cmake-3.27.7-1.fc37.x86_64.rpm         1.8 MB/s | 7.8 MB     00:04
+    (39/56): cpp-12.3.1-1.fc37.x86_64.rpm           1.8 MB/s |  11 MB     00:05
+    ...
+    Complete!
+    --> c33f842f2fc
+    STEP 3/3: ENTRYPOINT ["bash"]
+    COMMIT fedoradebugging:37
+    --> 2412e124d12
+    Successfully tagged localhost/fedoradebugging:37
+    2412e124d1257914a70fde70289948f7880fdbd1d3b213c206ff691995ecc03e
+
+    $ docker image ls
+    REPOSITORY                         TAG         IMAGE ID      CREATED             SIZE
+    localhost/fedoradebugging          37          2412e124d125  About a minute ago  829 MB
+    registry.fedoraproject.org/fedora  37          4105b568d464  2 months ago        182 MB
+
+Notice that our image got the repository name prepended (``localhost``).
+This is a Podman thing, with the objective people specify the repositories
+their images come from, instead of risking pulling an image from different
+registries and risk pulling an infected image.
+
+.. _Create a container based on the image:
+
+Create a container based on the image
+=====================================
+
+Note: For toolchain containers, which is the typical use case
+for ns-3 testing, we use the ``run`` command instead. It creates
+and starts the container in a single command. You can jump directly
+to the `intended way to use toolchain containers`_, or continue
+reading in case you want to learn a bit more about Docker.
+
+Now that we have our container image, we can create a container
+based on it. It is like booting a brand-new computer with a freshly
+installed operating system and commonly used programs.
+
+Docker containers can be created with the following:
+
+.. sourcecode:: console
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
+
+    $ docker container create --name fedoradeb fedoradebugging:37
+    8cb9edea0dcfe4a2335dd5b73766a6985275f9ee3e0b6fd5ea5b03eedbd4bbb1
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE                         COMMAND     CREATED         STATUS      PORTS       NAMES
+    8cb9edea0dcf  localhost/fedoradebugging:37              13 seconds ago  Created                 fedoradeb
+
+.. _Start the container:
+
+Start the container
+===================
+
+Containers can be started with the following commands:
+
+.. sourcecode:: console
+
+    $ docker start fedoradeb
+    fedoradeb
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE                         COMMAND     CREATED             STATUS                     PORTS       NAMES
+    8cb9edea0dcf  localhost/fedoradebugging:37              About a minute ago  Exited (0) 13 seconds ago              fedoradeb
+
+As it can be seen, our container was started, then executed bash, but it
+was in a non-interactive session, so it doesn't wait for the user. The
+process created by the entrypoint then exited, and the container
+manager stopped the container.
+
+This is useful for containers running services, like web servers,
+but not useful at all to use it as a toolchain container. In the
+next section, we see the preferred way to start a container toolchain.
+
+.. _Access the container:
+
+Access the container
+====================
+
+For service containers, after starting the container with
+``start``, we can execute commands on the running container
+using ``exec``. We are going to use a different container for
+demonstration purposes.
+
+.. sourcecode:: console
+
+    $ docker pull nginx:latest
+    Resolving "nginx" using unqualified-search registries (/etc/containers/registries.conf)
+    Trying to pull docker.io/library/nginx:latest...
+    Getting image source signatures
+    Copying blob 398157bc5c51 done
+    Copying blob f0bd99a47d4a done
+    Copying blob f24a6f652778 done
+    Copying blob c57ee5000d61 done
+    Copying blob 9f3589a5fc50 done
+    Copying blob 9b0163235c08 done
+    Copying blob 1ef1c1a36ec2 done
+    Copying config b690f5f0a2 done
+    Writing manifest to image destination
+    Storing signatures
+    b690f5f0a2d535cee5e08631aa508fef339c43bb91d5b1f7d77a1a05cea021a8
+
+    $ docker container create --name nginx nginx:latest
+    b6fb5a96bed7552a8164ee20e20cb2dd39ac98f6a7c7c076d0e22b93bc85b988
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE                           COMMAND               CREATED         STATUS      PORTS       NAMES
+    b6fb5a96bed7  docker.io/library/nginx:latest  nginx -g daemon o...  16 seconds ago  Created                 nginx
+
+    $ docker start nginx
+    nginx
+
+    $ docker exec nginx whereis nginx
+    nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
+
+    $ docker exec -it nginx bash
+
+    root@b6fb5a96bed7:/# echo "Printing a message in the container"
+    Printing a message in the container
+
+    root@b6fb5a96bed7:/# exit
+    exit
+
+    $ docker container stop nginx
+    nginx
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS                    PORTS       NAMES
+    b6fb5a96bed7  docker.io/library/nginx:latest  nginx -g daemon o...  5 minutes ago  Exited (0) 7 seconds ago              nginx
+
+    $ docker container rm nginx
+    b6fb5a96bed7552a8164ee20e20cb2dd39ac98f6a7c7c076d0e22b93bc85b988
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS                    PORTS       NAMES
+
+    $ docker image ls
+    REPOSITORY                         TAG         IMAGE ID      CREATED         SIZE
+    docker.io/library/nginx            latest      b690f5f0a2d5  3 months ago    191 MB
+
+    $ docker image rm nginx:latest
+    Untagged: docker.io/library/nginx:latest
+    Deleted: b690f5f0a2d535cee5e08631aa508fef339c43bb91d5b1f7d77a1a05cea021a8
+
+.. _intended way to use toolchain containers:
+
+The intended way to access toolchain containers
+###############################################
+
+Other than ``start/stop/exec``, Docker also has a ``run`` option, that builds a
+brand-new container from the container image for each time it is executed.
+This is the intended way to use toolchain containers.
+
+.. sourcecode:: console
+
+    $ docker run -it fedoradebugging:37
+
+    [root@6fa29fa742c5 /]# echo "Printing a message in the container"
+    Printing a message in the container
+
+    [root@6fa29fa742c5 /]# exit
+    exit
+
+    $
+
+Now we need to access files that are not inside the container volume. To do
+this, we can mount an external volume as a local directory.
+
+.. sourcecode:: console
+
+    $ mkdir -p ./external/ns-3-dev
+
+    $ echo "hello" > ./external/ns-3-dev/msg.txt
+
+    $ docker run -it -v ./external/ns-3-dev:/internal/ns-3-dev fedoradebugging:37
+
+    [root@6fa29fa742c5 /]# cat /internal/ns-3-dev/msg.txt
+    hello
+
+    [root@8f0fd2eded04 /]# exit
+    exit
+
+    $
+
+With this, we can point to the real ns-3-dev directory and work as usual.
+
+.. sourcecode:: console
+
+    $ docker run -it -v ./ns-3-dev:/ns-3-dev fedoradebugging:37
+
+    [root@067a8b748816 /]# cd ns-3-dev/
+
+    [root@067a8b748816 ns-3-dev]# ./ns3 configure
+    Warn about uninitialized values.
+    -- The CXX compiler identification is GNU 12.3.1
+    ...
+    -- ---- Summary of ns-3 settings:
+    Build profile                 : default
+    Build directory               : /ns-3-dev/build
+    Build with runtime asserts    : ON
+    Build with runtime logging    : ON
+    Build version embedding       : OFF (not requested)
+    ...
+    -- Configuring done (26.5s)
+    -- Generating done (11.6s)
+    -- Build files have been written to: /ns-3-dev/cmake-cache
+    Finished executing the following commands:
+    /usr/bin/cmake3 -S /ns-3-dev -B /ns-3-dev/cmake-cache -DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF -DNS3_NATIVE_OPTIMIZATIONS=OFF -G Ninja -
+    -warn-uninitialized
+
+The container will be automatically stopped after exiting.
+
+.. sourcecode:: console
+
+    [root@067a8b748816 ns-3-dev]# exit
+    exit
+
+    $ docker container ls
+    CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
+
+
+.. _Stop the container:
+
+Stop the container
+==================
+
+For long-running, non-interactive containers, use:
+
+.. sourcecode:: console
+
+    $ docker container stop containername
+
+
+.. _Deleting the container:
+
+Deleting the container
+======================
+
+To delete a container, it must be stopped first.
+If it isn't listed in ``docker container ls``, that
+is already the case.
+
+.. sourcecode:: console
+
+    $ docker container ls -a
+    CONTAINER ID  IMAGE                         COMMAND     CREATED        STATUS                      PORTS       NAMES
+    067a8b748816  localhost/fedoradebugging:37              3 minutes ago  Exited (0) 5 seconds ago                relaxed_carver
+
+    $ docker container rm relaxed_carver
+    067a8b748816715d93ede9099132d943c04b13fcc23b3b8a7e21d23c1096cc2a
+
+.. _Publishing the container image:
+
+Publishing the container image
+==============================
+
+To publish an image, you need to tag it prepending the
+Docker registry you are submitting your image.
+
+For example, to submit our ``localhost/fedoradebugging:37``
+to the Docker.io registry, we would add the
+``docker.io/username/fedoradebugging:37``.
+
+.. sourcecode:: console
+
+    $ docker tag localhost/fedoradebugging:37 docker.io/username/fedoradebugging:37
+
+    $ docker push docker.io/username/fedoradebugging:37
+
+If you don't want to push your image to a public registry, you can
+run your own registry inside a container. The following command
+will set up a registry container, and expose it to port 5000 of
+the host device. This allows third parties to access the service
+hosted inside the container, as long as the host firewall allows it.
+
+.. sourcecode:: console
+
+    $ docker run -d -p 5000:5000 --restart always --name registry registry:2
+    Resolved "registry" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
+    Trying to pull docker.io/library/registry:2...
+    Getting image source signatures
+    Copying blob 619be1103602 done
+    Copying blob d1a4f6454cb2 done
+    Copying blob 0da701e3b4d6 done
+    Copying blob 2ba4b87859f5 done
+    Copying blob 14a4d5d702c7 done
+    Copying config a8781fe3b7 done
+    Writing manifest to image destination
+    Storing signatures
+    fa61d0ba582bc4953d81163abdb174dea937c15f5882a5395a857dfa8b8fc4fc
+
+    $ docker tag fedoradebugging:37 localhost:5000/fedoradebugging:37
+
+    $ docker push localhost:5000/fedoradebugging:37
+
+
+Note: you can also publish your container images to GitLab and GitHub
+container registries. You first need to login into the registries,
+then set the appropriate tag for the registry and push the image.
+
+Here is an example for GitLab:
+
+.. sourcecode:: console
+
+    $ docker login -u user_name registry_url
+
+    $ docker tag fedoradebugging:37 registry.gitlab.com/user_name/project_name/fedoradebugging:37
+
+    $ docker push registry.gitlab.com/user_name/project_name/fedoradebugging:37
+    Getting image source signatures
+    Copying blob cb6b836430b4 [================================>-----] 152.0MiB / 173.3MiB
+    Copying blob cb6b836430b4 [================================>-----] 152.0MiB / 173.3MiB
+    Copying blob cb6b836430b4 [================================>-----] 152.0MiB / 173.3MiB
+    Copying blob cb6b836430b4 [================================>-----] 152.0MiB / 173.3MiB
+    Copying blob cb6b836430b4 [================================>-----] 152.0MiB / 173.3MiB
+    Getting image source signatures
+    Copying blob cb6b836430b4 done
+    Copying config 4105b568d4 done
+    Writing manifest to image destination
+    Storing signatures
+
+    $ docker image prune -a
+    WARNING! This command removes all images without at least one container associated with them.
+    Are you sure you want to continue? [y/N] y
+    4105b568d464732d3ea6a3ce9a0095f334fa7aa86fdd1129f288d2687801d87d
+
+    $ docker image ls
+    REPOSITORY  TAG         IMAGE ID    CREATED     SIZE
+
+    $ docker pull registry.gitlab.com/user_name/project_name/fedoradebugging:37
+    Trying to pull registry.gitlab.com/user_name/project_name/fedoradebugging:37...
+    Getting image source signatures
+    Copying blob 6eb8dda2c1ca done
+    Copying config 4105b568d4 done
+    Writing manifest to image destination
+    Storing signatures
+    4105b568d464732d3ea6a3ce9a0095f334fa7aa86fdd1129f288d2687801d87d
+
+
+We can also build our docker images directly from the GitLab CI and publish them
+with the following jobs:
+
+.. sourcecode:: yaml
+
+    .build-and-register-docker-image:
+      image: docker
+      services:
+        - docker:dind
+      before_script:
+        - mkdir -p $HOME/.docker
+        - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
+      script:
+        - docker build --pull -f $DOCKERFILE -t $CI_REGISTRY_IMAGE/$DOCKERTAG .
+        - docker push $CI_REGISTRY_IMAGE/$DOCKERTAG
+
+    fedoradebugging37:
+      extends:
+        - .build-and-register-docker-image
+      variables:
+        DOCKERFILE: "Dockerfile.fedoradebugging37.txt"
+        DOCKERTAG: "fedoradebugging:37"
+
+.. _Deleting the container image:
+
+Deleting the container image
+============================
+
+Same command we have shown a few times in the previous command.
+
+.. sourcecode:: console
+
+    $ docker image ls
+    REPOSITORY                         TAG         IMAGE ID      CREATED            SIZE
+    localhost/fedoradebugging          37          2412e124d125  About an hour ago  829 MB
+    localhost:5000/fedoradebugging     37          2412e124d125  About an hour ago  829 MB
+
+    $ docker image rm localhost:5000/fedoradebugging:37
+
+    $ docker image ls
+    REPOSITORY                         TAG         IMAGE ID      CREATED            SIZE
+    localhost/fedoradebugging          37          2412e124d125  About an hour ago  829 MB
+
+    $ docker image rm localhost/fedoradebugging:37
+    Untagged: localhost/fedoradebugging:37
+    Deleted: 2412e124d1257914a70fde70289948f7880fdbd1d3b213c206ff691995ecc03e
+    Deleted: c33f842f2fc0181b3b5f1d71456b0ffb8a2ec94e8d093f4873c61c492dd7e3dd
+
+.. _Podman containers:
+
+Podman containers
+*****************
+
+`Podman`_ is the drop-in replacement for Docker made by RedHat.
+You can install it and set up an alias using the following command.
+
+.. sourcecode:: console
+
+    echo alias docker=podman >> ~/.bashrc
+
+To get a docker-like experience, you might want to
+also change a few settings, such as search repositories for unqualified
+image names (without the prepended repository/registry).
+
+This can be done by adding the following line in ``/etc/containers/registries.conf``
+
+.. sourcecode:: text
+
+    unqualified-search-registries = ["registry.fedoraproject.org", "registry.access.redhat.com", "docker.io"]
+
+
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/manual/source/working-with-gitlab-ci-local.rst ns-3.42/doc/manual/source/working-with-gitlab-ci-local.rst
--- ns-3.41/doc/manual/source/working-with-gitlab-ci-local.rst	2024-02-09 14:44:07.781789300 -0800
+++ ns-3.42/doc/manual/source/working-with-gitlab-ci-local.rst	2024-05-29 15:29:46.876073000 -0700
@@ -1,6 +1,7 @@
 .. include:: replace.txt
 .. highlight:: bash
 
+.. _Working with gitlab-ci-local:
 
 Working with gitlab-ci-local
 ----------------------------
@@ -11,13 +12,13 @@
 .. _crypto miners abuse : https://about.gitlab.com/blog/2021/05/17/prevent-crypto-mining-abuse/
 .. _GitLab-CI-local : https://github.com/firecow/gitlab-ci-local
 .. _GitLab CI : https://docs.gitlab.com/ee/ci/
-.. _Docker : https://docs.docker.com/desktop/
-.. _rootless mode : https://docs.docker.com/engine/security/rootless/
 
 The ns-3 project repository is currently hosted in GitLab, which includes
 `continuous integration (CI)`_ tools to automate build, tests, packaging and
 distribution of software. The CI works based on jobs, that are defined
-on YAML files.
+in YAML files and run inside containers.
+
+See :ref:`Working with Docker` for more information about containers in general.
 
 The ns-3 GitLab CI files are located in ``ns-3-dev/utils/tests/``.
 The main GitLab CI file is ``gitlab-ci.yml``. The different jobs
@@ -44,16 +45,16 @@
 repositories that fill up the CI job queues with failed jobs due to
 script errors.
 
-GitLab-CI-local relies on `Docker`_ to setup the environment to execute
-the jobs.
+GitLab-CI-local relies on :ref:`Docker containers`
+to setup the environment to execute the jobs.
 
 Note: Docker is usually setup in root mode, requiring
 frequent use of administrative permissions/sudo. However,
 this is highly discouraged. You can configure Docker to run
-in `rootless mode`_. From this point onwards, we assume Docker is configured
-in `rootless mode`_.
+in :ref:`Docker rootless mode <Install Docker>`. From this point onwards, we assume Docker is configured
+in :ref:`Docker rootless mode <Install Docker>`.
 
-After installing both `Docker`_ in `rootless mode`_ and `GitLab-CI-local`_,
+After installing both :ref:`Docker <Docker containers>` and `GitLab-CI-local`_,
 the ns-3 jobs can be listed using the following command:
 
 .. sourcecode:: bash
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/models/Makefile ns-3.42/doc/models/Makefile
--- ns-3.41/doc/models/Makefile	2024-02-09 14:44:07.781789300 -0800
+++ ns-3.42/doc/models/Makefile	2024-05-29 15:29:46.876073000 -0700
@@ -111,6 +111,7 @@
 	figures/testbed.dia \
 	figures/emulated-channel.dia \
 	$(SRC)/antenna/doc/source/figures/antenna-coordinate-system.dia	\
+	$(SRC)/antenna/doc/source/figures/circular-antenna-pattern.png	\
 	$(SRC)/applications/doc/http-embedded-object-size.png \
 	$(SRC)/applications/doc/http-main-object-size.png \
 	$(SRC)/applications/doc/http-num-of-embedded-objects.png \
@@ -141,6 +142,7 @@
 	$(SRC)/wifi/doc/source/figures/PhyEntityHierarchy.dia \
 	$(SRC)/wifi/doc/source/figures/WifiPpduHierarchy.dia \
 	$(SRC)/wifi/doc/source/figures/FemHierarchy.dia \
+	$(SRC)/wifi/doc/source/figures/wifi-phy-rx-trace-helper.dia \
 	$(SRC)/wifi/doc/source/figures/snir.dia \
 	$(SRC)/wifi/doc/source/figures/ack-su-format.pdf \
 	$(SRC)/wifi/doc/source/figures/ack-su-format.png \
@@ -388,6 +390,7 @@
 	$(FIGURES)/PhyEntityHierarchy.eps \
 	$(FIGURES)/WifiPpduHierarchy.eps \
 	$(FIGURES)/FemHierarchy.eps \
+	$(FIGURES)/wifi-phy-rx-trace-helper.eps \
 	$(FIGURES)/snir.eps \
 	$(FIGURES)/WimaxArchitecture.eps \
 	$(FIGURES)/epc-ctrl-arch.eps \
@@ -577,7 +580,7 @@
 	@if test x$($@_width) != x; then $(RESCALE) $($@_width) $@ ; fi
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/models/source/conf.py ns-3.42/doc/models/source/conf.py
--- ns-3.41/doc/models/source/conf.py	2024-02-09 14:45:45.430484000 -0800
+++ ns-3.42/doc/models/source/conf.py	2024-05-29 15:30:03.724115800 -0700
@@ -74,16 +74,16 @@
 # built documents.
 #
 # The short X.Y version.
-version = "ns-3.41"
+version = "ns-3.42"
 # The full version, including alpha/beta/rc tags.
-release = "ns-3.41"
+release = "ns-3.42"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+# language = None
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/ns3_html_theme/ns3_doxy_footer.html ns-3.42/doc/ns3_html_theme/ns3_doxy_footer.html
--- ns-3.41/doc/ns3_html_theme/ns3_doxy_footer.html	2024-02-09 14:44:07.781789300 -0800
+++ ns-3.42/doc/ns3_html_theme/ns3_doxy_footer.html	2024-05-29 15:29:46.876073000 -0700
@@ -1,6 +1,5 @@
 <!-- ns-3 doxygen header, based on
-     HTML header for doxygen 1.8.3.1
-     Verified compatible with 1.8.6
+     HTML header for doxygen 1.10.0
 -->
 <!-- start footer part -->
 <!--BEGIN GENERATE_TREEVIEW-->
@@ -8,15 +7,15 @@
   <ul>
     $navpath
     <li class="footer">$generatedby
-    <a href="http://www.doxygen.org/index.html">
-    <img class="footer" src="$relpath$doxygen.svg" alt="doxygen"/></a> $doxygenversion </li>
+    <a href="https://www.doxygen.org/index.html">
+    <img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
   </ul>
 </div>
 <!--END GENERATE_TREEVIEW-->
 <!--BEGIN !GENERATE_TREEVIEW-->
 <hr class="footer"/><address class="footer"><small>
-$generatedby &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="$relpath$doxygen.svg" alt="doxygen"/>
+$generatedby &#160;<a href="https://www.doxygen.org/index.html">
+<img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/>
 </a> $doxygenversion
 </small></address>
 <!--END !GENERATE_TREEVIEW-->
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/ns3_html_theme/ns3_doxy_header.html ns-3.42/doc/ns3_html_theme/ns3_doxy_header.html
--- ns-3.41/doc/ns3_html_theme/ns3_doxy_header.html	2024-02-09 14:44:07.781789300 -0800
+++ ns-3.42/doc/ns3_html_theme/ns3_doxy_header.html	2024-05-29 15:29:46.876073000 -0700
@@ -1,28 +1,34 @@
 <!-- ns-3 doxygen header, based on
-     HTML header for doxygen 1.8.3.1
-     Verified compatible with 1.8.6
+     HTML header for doxygen 1.10.0
 -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
 <head>
 <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta http-equiv="X-UA-Compatible" content="IE=11"/>
 <meta name="generator" content="Doxygen $doxygenversion"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
 <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
 <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<!--BEGIN PROJECT_ICON-->
+<link rel="icon" href="$relpath^favicon.ico" type="image/x-icon" />
+<!--END PROJECT_ICON-->
 <link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
 <script type="text/javascript" src="$relpath^jquery.js"></script>
 <script type="text/javascript" src="$relpath^dynsections.js"></script>
+<!--BEGIN COPY_CLIPBOARD-->
+<script type="text/javascript" src="$relpath^clipboard.js"></script>
+<!--END COPY_CLIPBOARD-->
 $treeview
 $search
 $mathjax
+$darkmode
 <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
 $extrastylesheet
-    <link href="$relpath$favicon.ico" rel="shortcut icon" type="image/ico"></link>
     <script type="text/javascript" src="$relpath$drop-down-menu.js"></script>
     <script type="text/javascript" src="$relpath$ns3_version.js"></script>
     <script type="text/javascript" src="$relpath$ns3_links.js"></script>
-  </head>
+</head>
 <body>
     <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
 
@@ -30,12 +36,12 @@
     <div id="titlearea">
       <table cellspacing="0" cellpadding="0" width="100%">
         <tbody>
-          <tr style="height: 56px;">
+          <tr id="projectrow">
             <td id="projectlogo">
               <a id="ns3_home1"
-		 href="https://www.nsnam.org/">
-		<img alt="ns-3 Logo"
-                     src="$relpath$$projectlogo"/>
+                 href="https://www.nsnam.org/">
+                 <img alt="ns-3 Logo"
+                      src="$relpath$$projectlogo"/>
               </a>
             </td>
             <td id="projecttext">
@@ -48,19 +54,19 @@
                 <ul >
                   <li style="background-image:none">
                     <a id="ns3_home2"
-                         href="https://www.nsnam.org/"
-                         >&nbsp;&nbsp;Home</a>
+                       href="https://www.nsnam.org/"
+                       >&nbsp;&nbsp;Home</a>
                   </li>
                   <li><span
                         onmouseover="mopen('mTuts')"
                         onmouseout="mclosetime()"
                           >Tutorials &nbsp;&#x25BC;</span>
                       <div id="mTuts"
-                          onmouseover="mcancelclosetime()"
-                          onmouseout="mclosetime()">
+                           onmouseover="mcancelclosetime()"
+                           onmouseout="mclosetime()">
                         <a id="ns3_tut"
                            href="/docs/tutorial/html/index.html"
-                            >English</a><br/>
+                           >English</a><br/>
                       </div>
                   </li>
                   <li><span
@@ -68,8 +74,8 @@
                         onmouseout="mclosetime()"
                           >Documentation &nbsp;&#x25BC;</span>
                       <div id="mDocs"
-                          onmouseover="mcancelclosetime()"
-                          onmouseout="mclosetime()">
+                           onmouseover="mcancelclosetime()"
+                           onmouseout="mclosetime()">
                         <a id="ns3_ins"
                            href="/docs/installation/html/index.html"
                            >Installation</a><br/>
@@ -92,16 +98,16 @@
                         onmouseout="mclosetime()"
                           >Development &nbsp;&#x25BC;</span>
                       <div id="mDev"
-                          onmouseover="mcancelclosetime()"
-                          onmouseout="mclosetime()">
+                           onmouseover="mcancelclosetime()"
+                           onmouseout="mclosetime()">
                         <a id="ns3_api"
                            href="/docs/doxygen/html/index.html"
                            >API Docs</a><br/>
                         <a id="ns3_bugs"
-                         href="https://gitlab.com/nsnam/ns-3-dev/-/issues"
+                           href="https://gitlab.com/nsnam/ns-3-dev/-/issues"
                            >Issue Tracker</a><br/>
                         <a id="ns3_merge"
-                         href="https://gitlab.com/nsnam/ns-3-dev/-/merge_requests"
+                           href="https://gitlab.com/nsnam/ns-3-dev/-/merge_requests"
                            >Merge Requests</a><br/>
                       </div>
                   </li>
@@ -115,7 +121,7 @@
           </tr>
         </tbody>
       </table>
-      <script  type="text/javascript">ns3_write_links()</script>
+      <script type="text/javascript">ns3_write_links()</script>
     </div>
 <!--END TITLEAREA-->
 <!-- end header part -->
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/ns3_html_theme/static/drop-down-menu.js ns-3.42/doc/ns3_html_theme/static/drop-down-menu.js
--- ns-3.41/doc/ns3_html_theme/static/drop-down-menu.js	2024-02-09 14:44:07.785789300 -0800
+++ ns-3.42/doc/ns3_html_theme/static/drop-down-menu.js	2024-05-29 15:29:46.876073000 -0700
@@ -30,9 +30,9 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 
-var timeout	= 250;
-var closetimer	= 0;
-var ddmenuitem	= 0;
+var timeout = 250;
+var closetimer = 0;
+var ddmenuitem = 0;
 
 // open hidden layer
 function mopen(id)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/ns3_html_theme/static/ns3_stylesheet.css ns-3.42/doc/ns3_html_theme/static/ns3_stylesheet.css
--- ns-3.41/doc/ns3_html_theme/static/ns3_stylesheet.css	2024-02-09 14:44:07.785789300 -0800
+++ ns-3.42/doc/ns3_html_theme/static/ns3_stylesheet.css	2024-05-29 15:29:46.876073000 -0700
@@ -94,6 +94,11 @@
     z-index: 10000;
 }
 
+#projectrow
+{
+    height: 56px;
+}
+
 #projectlogo {
     color: white;
     margin: 10px;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/ns3_html_theme/static/sidebar.js ns-3.42/doc/ns3_html_theme/static/sidebar.js
--- ns-3.41/doc/ns3_html_theme/static/sidebar.js	2024-02-09 14:44:07.785789300 -0800
+++ ns-3.42/doc/ns3_html_theme/static/sidebar.js	2024-05-29 15:29:46.876073000 -0700
@@ -98,9 +98,9 @@
     // find the height of the viewport to center the '<<' in the page
     var viewport_height;
     if (window.innerHeight)
- 	  viewport_height = window.innerHeight;
+      viewport_height = window.innerHeight;
     else
-	  viewport_height = $(window).height();
+      viewport_height = $(window).height();
     sidebarbutton.find('span').css({
         'display': 'block',
         'margin-top': (viewport_height - sidebar.position().top - 20) / 2
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/ns3_html_theme/theme.conf ns-3.42/doc/ns3_html_theme/theme.conf
--- ns-3.41/doc/ns3_html_theme/theme.conf	2024-02-09 14:44:07.785789300 -0800
+++ ns-3.42/doc/ns3_html_theme/theme.conf	2024-05-29 15:29:46.876073000 -0700
@@ -22,29 +22,28 @@
 externalrefs = false
 
 bgcolor          = white
-textcolor	 = black
+textcolor        = black
 linkcolor        = #91A501
 visitedlinkcolor = #91A501
 
 headbgcolor      = #E3E3E3
-headtextcolor 	 = #373737
-headlinkcolor 	 = #91A501
+headtextcolor    = #373737
+headlinkcolor    = #91A501
 
-relbarbgcolor 	 = #D5D5D5
+relbarbgcolor    = #D5D5D5
 relbarlinkcolor  = #373737
 relbartextcolor  = #373737
 
-sidebarbgcolor 	 = #FAFAFA
+sidebarbgcolor   = #FAFAFA
 sidebartextcolor = #373737
 sidebarlinkcolor = #91A501
 sidebarbtncolor  = #D5D5D5
 
 footerbgcolor    = #D5D5D5
-footertextcolor	 = #364D7C
+footertextcolor  = #364D7C
 
 codebgcolor      = #FBFCFD
 codetextcolor    = black
 
 bodyfont = 'Lucida Grande', Verdana, Geneva, Arial, sans-serif
 headfont = 'Lucida Grande', Verdana, Geneva, Arial, sans-serif
-
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/tutorial/Makefile ns-3.42/doc/tutorial/Makefile
--- ns-3.41/doc/tutorial/Makefile	2024-02-09 14:44:07.785789300 -0800
+++ ns-3.42/doc/tutorial/Makefile	2024-05-29 15:29:46.876073000 -0700
@@ -2,7 +2,7 @@
 #
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/tutorial/source/conf.py ns-3.42/doc/tutorial/source/conf.py
--- ns-3.41/doc/tutorial/source/conf.py	2024-02-09 14:45:45.430484000 -0800
+++ ns-3.42/doc/tutorial/source/conf.py	2024-05-29 15:30:03.724115800 -0700
@@ -71,16 +71,16 @@
 # built documents.
 #
 # The short X.Y version.
-version = "ns-3.41"
+version = "ns-3.42"
 # The full version, including alpha/beta/rc tags.
-release = "ns-3.41"
+release = "ns-3.42"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+# language = None
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/tutorial/source/getting-started.rst ns-3.42/doc/tutorial/source/getting-started.rst
--- ns-3.41/doc/tutorial/source/getting-started.rst	2024-02-09 14:44:07.829789600 -0800
+++ ns-3.42/doc/tutorial/source/getting-started.rst	2024-05-29 15:29:46.904073000 -0700
@@ -61,7 +61,7 @@
 for various systems, available at
 https://www.nsnam.org/docs/installation/html/index.html.
 
-As of the most recent |ns3| release (ns-3.41), the following tools
+As of the most recent |ns3| release (ns-3.42), the following tools
 are needed to get started with |ns3|:
 
 ============  ===========================================================
@@ -116,21 +116,21 @@
   $ cd
   $ mkdir workspace
   $ cd workspace
-  $ wget https://www.nsnam.org/release/ns-allinone-3.41.tar.bz2
-  $ tar xjf ns-allinone-3.41.tar.bz2
+  $ wget https://www.nsnam.org/release/ns-allinone-3.42.tar.bz2
+  $ tar xjf ns-allinone-3.42.tar.bz2
 
 Notice the use above of the ``wget`` utility, which is a command-line
 tool to fetch objects from the web; if you do not have this installed,
 you can use a browser for this step.
 
 Following these steps, if you change into the directory
-``ns-allinone-3.41``, you should see a number of files and directories
+``ns-allinone-3.42``, you should see a number of files and directories
 
 .. sourcecode:: text
 
-  $ cd ns-allinone-3.41
+  $ cd ns-allinone-3.42
   $ ls
-  bake  build.py  constants.py  netanim-3.109 ns-3.41  README.md  util.py
+  bake  build.py  constants.py  netanim-3.109 ns-3.42  README.md  util.py
 
 You are now ready to build the base |ns3| distribution and may skip ahead
 to the section on building |ns3|.
@@ -180,7 +180,7 @@
 
 .. sourcecode:: console
 
-  $ python3 download.py -n ns-3.41
+  $ python3 download.py -n ns-3.42
 
 After this step, the additional repositories of |ns3|, bake, pybindgen,
 and netanim will be downloaded to the ``ns-3-allinone`` directory.
@@ -249,9 +249,9 @@
 
 There are a few configuration targets available:
 
-1.  ``ns-3.41``:  the code corresponding to the release
+1.  ``ns-3.42``:  the code corresponding to the release
 2.  ``ns-3-dev``:  a similar module but using the development code tree
-3.  ``ns-allinone-3.41``:  the module that includes other optional features
+3.  ``ns-allinone-3.42``:  the module that includes other optional features
     such as bake build system, netanim animator, and pybindgen
 4.  ``ns-3-allinone``:  similar to the released version of the allinone
     module, but for development code.
@@ -268,7 +268,7 @@
 `"ns-3 Releases"
 <https://www.nsnam.org/releases>`_
 web page and clicking on the latest release link.  We'll proceed in
-this tutorial example with ``ns-3.41``.
+this tutorial example with ``ns-3.42``.
 
 We are now going to use the bake tool to pull down the various pieces of
 |ns3| you will be using.  First, we'll say a word about running bake.
@@ -297,7 +297,7 @@
 
 .. sourcecode:: console
 
-  $ ./bake.py configure -e ns-allinone-3.41
+  $ ./bake.py configure -e ns-allinone-3.42
 
 Next, we'll ask bake to check whether we have enough tools to download
 various components.  Type:
@@ -347,7 +347,7 @@
   >> Downloading click-ns-3.37 - OK
   >> Downloading BRITE - OK
   >> Downloading openflow-dev - OK
-  >> Downloading ns-3.41 (target directory:ns-3.41) - OK
+  >> Downloading ns-3.42 (target directory:ns-3.42) - OK
 
 The above suggests that three sources have been downloaded.  Check the
 ``source`` directory now and type ``ls``; one should see:
@@ -356,7 +356,7 @@
 
   $ cd source
   $ ls
-  BRITE  click-ns-3.37  netanim-3.109  ns-3.41  openflow-dev
+  BRITE  click-ns-3.37  netanim-3.109  ns-3.42  openflow-dev
 
 You are now ready to build the |ns3| distribution.
 
@@ -386,7 +386,7 @@
 
 If you downloaded
 using a tarball you should have a directory called something like
-``ns-allinone-3.41`` under your ``~/workspace`` directory.
+``ns-allinone-3.42`` under your ``~/workspace`` directory.
 Type the following:
 
 .. sourcecode:: console
@@ -419,7 +419,7 @@
 .. sourcecode:: text
 
   >> Building netanim-3.109 - OK
-  >> Building ns-3.41 - OK
+  >> Building ns-3.42 - OK
 
 There may be failures to build all components, but the build will proceed
 anyway if the component is optional.
@@ -795,7 +795,7 @@
     | Wrapper  |                                 |                             |                               |                                 |
     | Macro    |                                 |                             |                               |                                 |
     +----------+---------------------------------+-----------------------------+-------------------------------+---------------------------------+
-    | Compiler | ``-Og -g``                      | ``-O2 -g``                  | ``-O3``                       | ``-O3``                         |
+    | Compiler | ``-Og -g``                      | ``-Os -g``                  | ``-O3``                       | ``-O3``                         |
     | Flags    |                                 |                             |                               | ``-march=native``               |
     |          |                                 |                             |                               | ``-mtune=native``               |
     +----------+---------------------------------+-----------------------------+-------------------------------+---------------------------------+
@@ -1159,7 +1159,7 @@
 
 The second, a more permanent solution, with the following command:
 
-.. sourcecode:: terminal
+.. sourcecode:: console
 
   > echo %PATH%
   C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/tutorial/source/quick-start.rst ns-3.42/doc/tutorial/source/quick-start.rst
--- ns-3.41/doc/tutorial/source/quick-start.rst	2024-02-09 14:44:07.833789600 -0800
+++ ns-3.42/doc/tutorial/source/quick-start.rst	2024-05-29 15:29:46.904073000 -0700
@@ -64,13 +64,13 @@
 
    ::
 
-    $ tar xjf ns-allinone-3.41.tar.bz2
+    $ tar xjf ns-allinone-3.42.tar.bz2
 
 3) Change into the |ns3| directory directly; e.g.
 
    ::
 
-    $ cd ns-allinone-3.41/ns-3.41
+    $ cd ns-allinone-3.42/ns-3.42
 
 The ns-allinone directory has some additional components but we are skipping
 over them here; one can work directly from the |ns3| source code directory.
@@ -92,12 +92,12 @@
 
   $ cd ns-3-dev
 
-If instead you want to try the most recent release (version 3.41 as of this
+If instead you want to try the most recent release (version 3.42 as of this
 writing), you can checkout a branch corresponding to that git tag:
 
 ::
 
-  $ git checkout -b ns-3.41-branch ns-3.41
+  $ git checkout -b ns-3.42-branch ns-3.42
 
 Building and testing ns-3
 *************************
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/doc/tutorial/source/tracing.rst ns-3.42/doc/tutorial/source/tracing.rst
--- ns-3.41/doc/tutorial/source/tracing.rst	2024-02-09 14:44:07.833789600 -0800
+++ ns-3.42/doc/tutorial/source/tracing.rst	2024-05-29 15:29:46.908073000 -0700
@@ -589,7 +589,7 @@
 which is a list of all of the nodes in the simulation.  Items in the
 list are referred to by indices into the list, so "/NodeList/7" refers
 to the eighth Node in the list of nodes created during the simulation
-(recall indices start at `0').  This reference is actually a
+(recall indices start at '0').  This reference is actually a
 ``Ptr<Node>`` and so is a subclass of an ``ns3::Object``.
 
 As described in the Object Model section of the |ns3| Manual, we make
@@ -1763,7 +1763,7 @@
   {
       m_running = false;
 
-      if (m_sendEvent.IsRunning())
+      if (m_sendEvent.IsPending())
       {
           Simulator::Cancel(m_sendEvent);
       }
@@ -1776,7 +1776,7 @@
 
 Every time a simulation event is scheduled, an ``Event`` is created.
 If the ``Event`` is pending execution or executing, its method
-``IsRunning`` will return ``true``.  In this code, if ``IsRunning()``
+``IsPending`` will return ``true``.  In this code, if ``IsPending()``
 returns true, we ``Cancel`` the event which removes it from the
 simulator event queue.  By doing this, we break the chain of events
 that the ``Application`` is using to keep sending its ``Packets`` and
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/energy/energy-model-example.cc ns-3.42/examples/energy/energy-model-example.cc
--- ns-3.41/examples/energy/energy-model-example.cc	2024-02-09 14:44:07.833789600 -0800
+++ ns-3.42/examples/energy/energy-model-example.cc	2024-05-29 15:29:46.908073000 -0700
@@ -31,6 +31,7 @@
 #include <vector>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("EnergyExample");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/energy/energy-model-with-harvesting-example.cc ns-3.42/examples/energy/energy-model-with-harvesting-example.cc
--- ns-3.41/examples/energy/energy-model-with-harvesting-example.cc	2024-02-09 14:44:07.833789600 -0800
+++ ns-3.42/examples/energy/energy-model-with-harvesting-example.cc	2024-05-29 15:29:46.908073000 -0700
@@ -60,6 +60,7 @@
 #include <vector>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("EnergyWithHarvestingExample");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/realtime/realtime-udp-echo.py ns-3.42/examples/realtime/realtime-udp-echo.py
--- ns-3.41/examples/realtime/realtime-udp-echo.py	2024-02-09 14:44:07.833789600 -0800
+++ ns-3.42/examples/realtime/realtime-udp-echo.py	2024-05-29 15:29:46.908073000 -0700
@@ -38,43 +38,41 @@
     # Allow the user to override any of the defaults and the above Bind() at
     # run-time, via command-line arguments
     #
-    cmd = ns.core.CommandLine()
+    cmd = ns.CommandLine()
     cmd.Parse(argv)
 
     #
     # But since this is a realtime script, don't allow the user to mess with
     # that.
     #
-    ns.core.GlobalValue.Bind(
-        "SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")
-    )
+    ns.GlobalValue.Bind("SimulatorImplementationType", ns.StringValue("ns3::RealtimeSimulatorImpl"))
 
     #
     # Explicitly create the nodes required by the topology (shown above).
     #
     print("Create nodes.")
-    n = ns.network.NodeContainer()
+    n = ns.NodeContainer()
     n.Create(4)
 
-    internet = ns.internet.InternetStackHelper()
+    internet = ns.InternetStackHelper()
     internet.Install(n)
 
     #
     # Explicitly create the channels required by the topology (shown above).
     #
     print("Create channels.")
-    csma = ns.csma.CsmaHelper()
-    csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000)))
-    csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2)))
-    csma.SetDeviceAttribute("Mtu", ns.core.UintegerValue(1400))
+    csma = ns.CsmaHelper()
+    csma.SetChannelAttribute("DataRate", ns.DataRateValue(ns.DataRate(5000000)))
+    csma.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(2)))
+    csma.SetDeviceAttribute("Mtu", ns.UintegerValue(1400))
     d = csma.Install(n)
 
     #
     # We've got the "hardware" in place.  Now we need to add IP addresses.
     #
     print("Assign IP Addresses.")
-    ipv4 = ns.internet.Ipv4AddressHelper()
-    ipv4.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
+    ipv4 = ns.Ipv4AddressHelper()
+    ipv4.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
     i = ipv4.Assign(d)
 
     print("Create Applications.")
@@ -83,10 +81,10 @@
     # Create a UdpEchoServer application on node one.
     #
     port = 9  # well-known echo port number
-    server = ns.applications.UdpEchoServerHelper(port)
+    server = ns.UdpEchoServerHelper(port)
     apps = server.Install(n.Get(1))
-    apps.Start(ns.core.Seconds(1.0))
-    apps.Stop(ns.core.Seconds(10.0))
+    apps.Start(ns.Seconds(1.0))
+    apps.Stop(ns.Seconds(10.0))
 
     #
     # Create a UdpEchoClient application to send UDP datagrams from node zero to
@@ -94,16 +92,16 @@
     #
     packetSize = 1024
     maxPacketCount = 500
-    interPacketInterval = ns.core.Seconds(0.01)
-    client = ns.applications.UdpEchoClientHelper(i.GetAddress(1).ConvertTo(), port)
-    client.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount))
-    client.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval))
-    client.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize))
+    interPacketInterval = ns.Seconds(0.01)
+    client = ns.UdpEchoClientHelper(i.GetAddress(1).ConvertTo(), port)
+    client.SetAttribute("MaxPackets", ns.UintegerValue(maxPacketCount))
+    client.SetAttribute("Interval", ns.TimeValue(interPacketInterval))
+    client.SetAttribute("PacketSize", ns.UintegerValue(packetSize))
     apps = client.Install(n.Get(0))
-    apps.Start(ns.core.Seconds(2.0))
-    apps.Stop(ns.core.Seconds(10.0))
+    apps.Start(ns.Seconds(2.0))
+    apps.Stop(ns.Seconds(10.0))
 
-    ascii = ns.network.AsciiTraceHelper()
+    ascii = ns.AsciiTraceHelper()
     csma.EnableAsciiAll(ascii.CreateFileStream("realtime-udp-echo.tr"))
     csma.EnablePcapAll("realtime-udp-echo", False)
 
@@ -111,9 +109,9 @@
     # Now, do the actual simulation.
     #
     print("Run Simulation.")
-    ns.core.Simulator.Stop(ns.Seconds(10))
-    ns.core.Simulator.Run()
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Stop(ns.Seconds(10))
+    ns.Simulator.Run()
+    ns.Simulator.Destroy()
     print("Done.")
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/routing/ripng-simple-network.cc ns-3.42/examples/routing/ripng-simple-network.cc
--- ns-3.41/examples/routing/ripng-simple-network.cc	2024-02-09 14:44:07.837789500 -0800
+++ ns-3.42/examples/routing/ripng-simple-network.cc	2024-05-29 15:29:46.908073000 -0700
@@ -82,7 +82,7 @@
     cmd.AddValue("printRoutingTables",
                  "Print routing tables at 30, 60 and 90 seconds",
                  printRoutingTables);
-    cmd.AddValue("showPings", "Show Ping6 reception", showPings);
+    cmd.AddValue("showPings", "Show Ping reception", showPings);
     cmd.AddValue("splitHorizonStrategy",
                  "Split Horizon strategy to use (NoSplitHorizon, SplitHorizon, PoisonReverse)",
                  SplitHorizon);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/routing/rip-simple-network.cc ns-3.42/examples/routing/rip-simple-network.cc
--- ns-3.41/examples/routing/rip-simple-network.cc	2024-02-09 14:44:07.837789500 -0800
+++ ns-3.42/examples/routing/rip-simple-network.cc	2024-05-29 15:29:46.908073000 -0700
@@ -82,7 +82,7 @@
     cmd.AddValue("printRoutingTables",
                  "Print routing tables at 30, 60 and 90 seconds",
                  printRoutingTables);
-    cmd.AddValue("showPings", "Show Ping6 reception", showPings);
+    cmd.AddValue("showPings", "Show Ping reception", showPings);
     cmd.AddValue("splitHorizonStrategy",
                  "Split Horizon strategy to use (NoSplitHorizon, SplitHorizon, PoisonReverse)",
                  SplitHorizon);
@@ -102,15 +102,15 @@
 
     if (SplitHorizon == "NoSplitHorizon")
     {
-        Config::SetDefault("ns3::Rip::SplitHorizon", EnumValue(RipNg::NO_SPLIT_HORIZON));
+        Config::SetDefault("ns3::Rip::SplitHorizon", EnumValue(Rip::NO_SPLIT_HORIZON));
     }
     else if (SplitHorizon == "SplitHorizon")
     {
-        Config::SetDefault("ns3::Rip::SplitHorizon", EnumValue(RipNg::SPLIT_HORIZON));
+        Config::SetDefault("ns3::Rip::SplitHorizon", EnumValue(Rip::SPLIT_HORIZON));
     }
     else
     {
-        Config::SetDefault("ns3::Rip::SplitHorizon", EnumValue(RipNg::POISON_REVERSE));
+        Config::SetDefault("ns3::Rip::SplitHorizon", EnumValue(Rip::POISON_REVERSE));
     }
 
     NS_LOG_INFO("Create nodes.");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/routing/simple-routing-ping6.py ns-3.42/examples/routing/simple-routing-ping6.py
--- ns-3.41/examples/routing/simple-routing-ping6.py	2024-02-09 14:44:07.837789500 -0800
+++ ns-3.42/examples/routing/simple-routing-ping6.py	2024-05-29 15:29:46.908073000 -0700
@@ -58,7 +58,7 @@
     internetv6.Install(all)
 
     # Create channels
-    csma = ns.csma.CsmaHelper()
+    csma = ns.CsmaHelper()
     csma.SetChannelAttribute("DataRate", ns.DataRateValue(ns.DataRate(5000000)))
     csma.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(2)))
     d1 = csma.Install(net1)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/traffic-control/tbf-example.cc ns-3.42/examples/traffic-control/tbf-example.cc
--- ns-3.41/examples/traffic-control/tbf-example.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/traffic-control/tbf-example.cc	2024-05-29 15:29:46.912073100 -0700
@@ -133,9 +133,9 @@
     ApplicationContainer apps;
 
     InetSocketAddress rmt(interfaces.GetAddress(0), port);
-    rmt.SetTos(0xb8);
-    AddressValue remoteAddress(rmt);
-    onoff.SetAttribute("Remote", remoteAddress);
+    onoff.SetAttribute("Remote", AddressValue(rmt));
+    onoff.SetAttribute("Tos", UintegerValue(0xb8));
+
     apps.Add(onoff.Install(nodes.Get(1)));
     apps.Start(Seconds(1.0));
     apps.Stop(Seconds(simulationTime + 0.1));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/traffic-control/traffic-control.cc ns-3.42/examples/traffic-control/traffic-control.cc
--- ns-3.41/examples/traffic-control/traffic-control.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/traffic-control/traffic-control.cc	2024-05-29 15:29:46.912073100 -0700
@@ -174,9 +174,8 @@
     ApplicationContainer apps;
 
     InetSocketAddress rmt(interfaces.GetAddress(0), port);
-    rmt.SetTos(0xb8);
-    AddressValue remoteAddress(rmt);
-    onoff.SetAttribute("Remote", remoteAddress);
+    onoff.SetAttribute("Remote", AddressValue(rmt));
+    onoff.SetAttribute("Tos", UintegerValue(0xb8));
     apps.Add(onoff.Install(nodes.Get(1)));
     apps.Start(Seconds(1.0));
     apps.Stop(Seconds(simulationTime + 0.1));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/tutorial/first.py ns-3.42/examples/tutorial/first.py
--- ns-3.41/examples/tutorial/first.py	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/tutorial/first.py	2024-05-29 15:29:46.912073100 -0700
@@ -29,41 +29,41 @@
 # //    point-to-point
 # //
 
-ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
-ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
+ns.LogComponentEnable("UdpEchoClientApplication", ns.LOG_LEVEL_INFO)
+ns.LogComponentEnable("UdpEchoServerApplication", ns.LOG_LEVEL_INFO)
 
-nodes = ns.network.NodeContainer()
+nodes = ns.NodeContainer()
 nodes.Create(2)
 
-pointToPoint = ns.point_to_point.PointToPointHelper()
-pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
-pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
+pointToPoint = ns.PointToPointHelper()
+pointToPoint.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
+pointToPoint.SetChannelAttribute("Delay", ns.StringValue("2ms"))
 
 devices = pointToPoint.Install(nodes)
 
-stack = ns.internet.InternetStackHelper()
+stack = ns.InternetStackHelper()
 stack.Install(nodes)
 
-address = ns.internet.Ipv4AddressHelper()
-address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
+address = ns.Ipv4AddressHelper()
+address.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
 
 interfaces = address.Assign(devices)
 
-echoServer = ns.applications.UdpEchoServerHelper(9)
+echoServer = ns.UdpEchoServerHelper(9)
 
 serverApps = echoServer.Install(nodes.Get(1))
-serverApps.Start(ns.core.Seconds(1.0))
-serverApps.Stop(ns.core.Seconds(10.0))
+serverApps.Start(ns.Seconds(1.0))
+serverApps.Stop(ns.Seconds(10.0))
 
 address = interfaces.GetAddress(1).ConvertTo()
-echoClient = ns.applications.UdpEchoClientHelper(address, 9)
-echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
-echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
-echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
+echoClient = ns.UdpEchoClientHelper(address, 9)
+echoClient.SetAttribute("MaxPackets", ns.UintegerValue(1))
+echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
+echoClient.SetAttribute("PacketSize", ns.UintegerValue(1024))
 
 clientApps = echoClient.Install(nodes.Get(0))
-clientApps.Start(ns.core.Seconds(2.0))
-clientApps.Stop(ns.core.Seconds(10.0))
+clientApps.Start(ns.Seconds(2.0))
+clientApps.Stop(ns.Seconds(10.0))
 
-ns.core.Simulator.Run()
-ns.core.Simulator.Destroy()
+ns.Simulator.Run()
+ns.Simulator.Destroy()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/tutorial/second.py ns-3.42/examples/tutorial/second.py
--- ns-3.41/examples/tutorial/second.py	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/tutorial/second.py	2024-05-29 15:29:46.912073100 -0700
@@ -43,61 +43,59 @@
 cmd.Parse(sys.argv)
 
 if verbose.value:
-    ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
-    ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
+    ns.LogComponentEnable("UdpEchoClientApplication", ns.LOG_LEVEL_INFO)
+    ns.LogComponentEnable("UdpEchoServerApplication", ns.LOG_LEVEL_INFO)
 nCsma.value = 1 if nCsma.value == 0 else nCsma.value
 
-p2pNodes = ns.network.NodeContainer()
+p2pNodes = ns.NodeContainer()
 p2pNodes.Create(2)
 
-csmaNodes = ns.network.NodeContainer()
+csmaNodes = ns.NodeContainer()
 csmaNodes.Add(p2pNodes.Get(1))
 csmaNodes.Create(nCsma.value)
 
-pointToPoint = ns.point_to_point.PointToPointHelper()
-pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
-pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
+pointToPoint = ns.PointToPointHelper()
+pointToPoint.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
+pointToPoint.SetChannelAttribute("Delay", ns.StringValue("2ms"))
 
 p2pDevices = pointToPoint.Install(p2pNodes)
 
-csma = ns.csma.CsmaHelper()
-csma.SetChannelAttribute("DataRate", ns.core.StringValue("100Mbps"))
-csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.NanoSeconds(6560)))
+csma = ns.CsmaHelper()
+csma.SetChannelAttribute("DataRate", ns.StringValue("100Mbps"))
+csma.SetChannelAttribute("Delay", ns.TimeValue(ns.NanoSeconds(6560)))
 
 csmaDevices = csma.Install(csmaNodes)
 
-stack = ns.internet.InternetStackHelper()
+stack = ns.InternetStackHelper()
 stack.Install(p2pNodes.Get(0))
 stack.Install(csmaNodes)
 
-address = ns.internet.Ipv4AddressHelper()
-address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
+address = ns.Ipv4AddressHelper()
+address.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
 p2pInterfaces = address.Assign(p2pDevices)
 
-address.SetBase(ns.network.Ipv4Address("10.1.2.0"), ns.network.Ipv4Mask("255.255.255.0"))
+address.SetBase(ns.Ipv4Address("10.1.2.0"), ns.Ipv4Mask("255.255.255.0"))
 csmaInterfaces = address.Assign(csmaDevices)
 
-echoServer = ns.applications.UdpEchoServerHelper(9)
+echoServer = ns.UdpEchoServerHelper(9)
 
 serverApps = echoServer.Install(csmaNodes.Get(nCsma.value))
-serverApps.Start(ns.core.Seconds(1.0))
-serverApps.Stop(ns.core.Seconds(10.0))
+serverApps.Start(ns.Seconds(1.0))
+serverApps.Stop(ns.Seconds(10.0))
 
-echoClient = ns.applications.UdpEchoClientHelper(
-    csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9
-)
-echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
-echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
-echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
+echoClient = ns.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9)
+echoClient.SetAttribute("MaxPackets", ns.UintegerValue(1))
+echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
+echoClient.SetAttribute("PacketSize", ns.UintegerValue(1024))
 
 clientApps = echoClient.Install(p2pNodes.Get(0))
-clientApps.Start(ns.core.Seconds(2.0))
-clientApps.Stop(ns.core.Seconds(10.0))
+clientApps.Start(ns.Seconds(2.0))
+clientApps.Stop(ns.Seconds(10.0))
 
-ns.internet.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
+ns.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
 
 pointToPoint.EnablePcapAll("second")
 csma.EnablePcap("second", csmaDevices.Get(1), True)
 
-ns.core.Simulator.Run()
-ns.core.Simulator.Destroy()
+ns.Simulator.Run()
+ns.Simulator.Destroy()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/tutorial/third.py ns-3.42/examples/tutorial/third.py
--- ns-3.41/examples/tutorial/third.py	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/tutorial/third.py	2024-05-29 15:29:46.912073100 -0700
@@ -59,112 +59,108 @@
     sys.exit(1)
 
 if verbose.value:
-    ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
-    ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
+    ns.LogComponentEnable("UdpEchoClientApplication", ns.LOG_LEVEL_INFO)
+    ns.LogComponentEnable("UdpEchoServerApplication", ns.LOG_LEVEL_INFO)
 
-p2pNodes = ns.network.NodeContainer()
+p2pNodes = ns.NodeContainer()
 p2pNodes.Create(2)
 
-pointToPoint = ns.point_to_point.PointToPointHelper()
-pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
-pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
+pointToPoint = ns.PointToPointHelper()
+pointToPoint.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
+pointToPoint.SetChannelAttribute("Delay", ns.StringValue("2ms"))
 
 p2pDevices = pointToPoint.Install(p2pNodes)
 
-csmaNodes = ns.network.NodeContainer()
+csmaNodes = ns.NodeContainer()
 csmaNodes.Add(p2pNodes.Get(1))
 csmaNodes.Create(nCsma.value)
 
-csma = ns.csma.CsmaHelper()
-csma.SetChannelAttribute("DataRate", ns.core.StringValue("100Mbps"))
-csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.NanoSeconds(6560)))
+csma = ns.CsmaHelper()
+csma.SetChannelAttribute("DataRate", ns.StringValue("100Mbps"))
+csma.SetChannelAttribute("Delay", ns.TimeValue(ns.NanoSeconds(6560)))
 
 csmaDevices = csma.Install(csmaNodes)
 
-wifiStaNodes = ns.network.NodeContainer()
+wifiStaNodes = ns.NodeContainer()
 wifiStaNodes.Create(nWifi.value)
 wifiApNode = p2pNodes.Get(0)
 
-channel = ns.wifi.YansWifiChannelHelper.Default()
-phy = ns.wifi.YansWifiPhyHelper()
+channel = ns.YansWifiChannelHelper.Default()
+phy = ns.YansWifiPhyHelper()
 phy.SetChannel(channel.Create())
 
-mac = ns.wifi.WifiMacHelper()
-ssid = ns.wifi.Ssid("ns-3-ssid")
+mac = ns.WifiMacHelper()
+ssid = ns.Ssid("ns-3-ssid")
 
-wifi = ns.wifi.WifiHelper()
+wifi = ns.WifiHelper()
 
-mac.SetType(
-    "ns3::StaWifiMac", "Ssid", ns.wifi.SsidValue(ssid), "ActiveProbing", ns.core.BooleanValue(False)
-)
+mac.SetType("ns3::StaWifiMac", "Ssid", ns.SsidValue(ssid), "ActiveProbing", ns.BooleanValue(False))
 staDevices = wifi.Install(phy, mac, wifiStaNodes)
 
-mac.SetType("ns3::ApWifiMac", "Ssid", ns.wifi.SsidValue(ssid))
+mac.SetType("ns3::ApWifiMac", "Ssid", ns.SsidValue(ssid))
 apDevices = wifi.Install(phy, mac, wifiApNode)
 
-mobility = ns.mobility.MobilityHelper()
+mobility = ns.MobilityHelper()
 mobility.SetPositionAllocator(
     "ns3::GridPositionAllocator",
     "MinX",
-    ns.core.DoubleValue(0.0),
+    ns.DoubleValue(0.0),
     "MinY",
-    ns.core.DoubleValue(0.0),
+    ns.DoubleValue(0.0),
     "DeltaX",
-    ns.core.DoubleValue(5.0),
+    ns.DoubleValue(5.0),
     "DeltaY",
-    ns.core.DoubleValue(10.0),
+    ns.DoubleValue(10.0),
     "GridWidth",
-    ns.core.UintegerValue(3),
+    ns.UintegerValue(3),
     "LayoutType",
-    ns.core.StringValue("RowFirst"),
+    ns.StringValue("RowFirst"),
 )
 
 mobility.SetMobilityModel(
     "ns3::RandomWalk2dMobilityModel",
     "Bounds",
-    ns.mobility.RectangleValue(ns.mobility.Rectangle(-50, 50, -50, 50)),
+    ns.RectangleValue(ns.Rectangle(-50, 50, -50, 50)),
 )
 mobility.Install(wifiStaNodes)
 
 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel")
 mobility.Install(wifiApNode)
 
-stack = ns.internet.InternetStackHelper()
+stack = ns.InternetStackHelper()
 stack.Install(csmaNodes)
 stack.Install(wifiApNode)
 stack.Install(wifiStaNodes)
 
-address = ns.internet.Ipv4AddressHelper()
-address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
+address = ns.Ipv4AddressHelper()
+address.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
 p2pInterfaces = address.Assign(p2pDevices)
 
-address.SetBase(ns.network.Ipv4Address("10.1.2.0"), ns.network.Ipv4Mask("255.255.255.0"))
+address.SetBase(ns.Ipv4Address("10.1.2.0"), ns.Ipv4Mask("255.255.255.0"))
 csmaInterfaces = address.Assign(csmaDevices)
 
-address.SetBase(ns.network.Ipv4Address("10.1.3.0"), ns.network.Ipv4Mask("255.255.255.0"))
+address.SetBase(ns.Ipv4Address("10.1.3.0"), ns.Ipv4Mask("255.255.255.0"))
 address.Assign(staDevices)
 address.Assign(apDevices)
 
-echoServer = ns.applications.UdpEchoServerHelper(9)
+echoServer = ns.UdpEchoServerHelper(9)
 
 serverApps = echoServer.Install(csmaNodes.Get(nCsma.value))
-serverApps.Start(ns.core.Seconds(1.0))
-serverApps.Stop(ns.core.Seconds(10.0))
+serverApps.Start(ns.Seconds(1.0))
+serverApps.Stop(ns.Seconds(10.0))
 
-echoClient = ns.applications.UdpEchoClientHelper(
-    csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9
-)
-echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
-echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
-echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))
+echoClient = ns.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma.value).ConvertTo(), 9)
+echoClient.SetAttribute("MaxPackets", ns.UintegerValue(1))
+echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
+echoClient.SetAttribute("PacketSize", ns.UintegerValue(1024))
 
 clientApps = echoClient.Install(wifiStaNodes.Get(nWifi.value - 1))
-clientApps.Start(ns.core.Seconds(2.0))
-clientApps.Stop(ns.core.Seconds(10.0))
+clientApps.Start(ns.Seconds(2.0))
+clientApps.Stop(ns.Seconds(10.0))
 
-ns.internet.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
+ns.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
 
-ns.core.Simulator.Stop(ns.core.Seconds(10.0))
+ns.Simulator.Stop(ns.Seconds(10.0))
 
 if tracing.value:
     phy.SetPcapDataLinkType(phy.DLT_IEEE802_11_RADIO)
@@ -172,5 +168,5 @@
     phy.EnablePcap("third", apDevices.Get(0))
     csma.EnablePcap("third", csmaDevices.Get(0), True)
 
-ns.core.Simulator.Run()
-ns.core.Simulator.Destroy()
+ns.Simulator.Run()
+ns.Simulator.Destroy()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/tutorial/tutorial-app.cc ns-3.42/examples/tutorial/tutorial-app.cc
--- ns-3.41/examples/tutorial/tutorial-app.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/tutorial/tutorial-app.cc	2024-05-29 15:29:46.912073100 -0700
@@ -76,7 +76,7 @@
 {
     m_running = false;
 
-    if (m_sendEvent.IsRunning())
+    if (m_sendEvent.IsPending())
     {
         Simulator::Cancel(m_sendEvent);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/examples-to-run.py ns-3.42/examples/wireless/examples-to-run.py
--- ns-3.41/examples/wireless/examples-to-run.py	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/examples-to-run.py	2024-05-29 15:29:46.912073100 -0700
@@ -25,7 +25,7 @@
     ("wifi-wired-bridging", "True", "True"),
     ("wifi-sleep", "True", "True"),
     ("wifi-blockack", "True", "True"),
-    ("wifi-timing-attributes --simulationTime=1", "True", "True"),
+    ("wifi-timing-attributes --simulationTime=1s", "True", "True"),
     (
         "wifi-power-adaptation-distance --manager=ns3::ParfWifiManager --outputFileName=parf --steps=5 --stepsSize=10",
         "True",
@@ -63,143 +63,143 @@
     ("wifi-ofdm-vht-validation", "True", "True"),
     ("wifi-ofdm-he-validation", "True", "True"),
     ("wifi-error-models-comparison", "True", "True"),
-    ("wifi-80211n-mimo --simulationTime=0.1 --step=10", "True", "True"),
+    ("wifi-80211n-mimo --simulationTime=0.1s --step=10", "True", "True"),
     (
-        "wifi-ht-network --simulationTime=0.2 --frequency=5 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=135",
+        "wifi-ht-network --simulationTime=0.2s --frequency=5 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=135",
         "True",
         "True",
     ),
     (
-        "wifi-ht-network --simulationTime=0.2 --frequency=5 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=132",
+        "wifi-ht-network --simulationTime=0.2s --frequency=5 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=132",
         "True",
         "True",
     ),
     (
-        "wifi-ht-network --simulationTime=0.2 --frequency=2.4 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=132",
+        "wifi-ht-network --simulationTime=0.2s --frequency=2.4 --useRts=0 --minExpectedThroughput=5 --maxExpectedThroughput=132",
         "True",
         "True",
     ),
     (
-        "wifi-ht-network --simulationTime=0.2 --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=129",
+        "wifi-ht-network --simulationTime=0.2s --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=129",
         "True",
         "True",
     ),
     (
-        "wifi-vht-network --simulationTime=0.2 --useRts=0  --minExpectedThroughput=5 --maxExpectedThroughput=583",
+        "wifi-vht-network --simulationTime=0.2s --useRts=0  --minExpectedThroughput=5 --maxExpectedThroughput=620",
         "True",
         "True",
     ),
     (
-        "wifi-vht-network --simulationTime=0.2 --useRts=1  --minExpectedThroughput=5 --maxExpectedThroughput=557",
+        "wifi-vht-network --simulationTime=0.2s --useRts=1  --minExpectedThroughput=5 --maxExpectedThroughput=557",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.25 --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=844",
+        "wifi-he-network --simulationTime=0.25s --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=844",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=0 --useExtendedBlockAck=1 --minExpectedThroughput=6 --maxExpectedThroughput=1033",
+        "wifi-he-network --simulationTime=0.3s --frequency=5 --useRts=0 --useExtendedBlockAck=1 --minExpectedThroughput=6 --maxExpectedThroughput=1033",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=745",
+        "wifi-he-network --simulationTime=0.3s --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=745",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.25 --frequency=2.4 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=238",
+        "wifi-he-network --simulationTime=0.25s --frequency=2.4 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=238",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=223",
+        "wifi-he-network --simulationTime=0.3s --frequency=2.4 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=223",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=4 --minExpectedThroughput=20 --maxExpectedThroughput=212",
+        "wifi-he-network --simulationTime=0.3s --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=4 --minExpectedThroughput=20 --maxExpectedThroughput=212",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --frequency=2.4 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --minExpectedThroughput=27 --maxExpectedThroughput=50",
+        "wifi-he-network --simulationTime=0.3s --frequency=2.4 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --minExpectedThroughput=21 --maxExpectedThroughput=56",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --minExpectedThroughput=31 --maxExpectedThroughput=290",
+        "wifi-he-network --simulationTime=0.3s --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --minExpectedThroughput=31 --maxExpectedThroughput=290",
         "True",
         "True",
     ),
     (
-        "wifi-he-network --simulationTime=0.3 --udp=1 --downlink=0 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --muSchedAccessReqInterval=50ms --minExpectedThroughput=46 --maxExpectedThroughput=327",
+        "wifi-he-network --simulationTime=0.3s --udp=1 --downlink=0 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --muSchedAccessReqInterval=50ms --minExpectedThroughput=46 --maxExpectedThroughput=327",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=550",
+        "wifi-eht-network --simulationTime=0.1s --frequency=5 --useRts=0 --minExpectedThroughput=6 --maxExpectedThroughput=760",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=0 --mpduBufferSize=1024 --frequency2=6 --minExpectedThroughput=12 --maxExpectedThroughput=550",
+        "wifi-eht-network --simulationTime=0.1s --frequency=5 --useRts=0 --mpduBufferSize=1024 --frequency2=6 --minExpectedThroughput=7 --maxExpectedThroughput=1444",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.1 --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=547",
+        "wifi-eht-network --simulationTime=0.1s --frequency=5 --useRts=1 --minExpectedThroughput=6 --maxExpectedThroughput=660",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=0 --mpduBufferSize=512 --frequency2=5 --minExpectedThroughput=12 --maxExpectedThroughput=500",
+        "wifi-eht-network --simulationTime=0.1s --frequency=2.4 --useRts=0 --mpduBufferSize=512 --frequency2=5 --minExpectedThroughput=7 --maxExpectedThroughput=512",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.1 --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=240",
+        "wifi-eht-network --simulationTime=0.1s --frequency=2.4 --useRts=1 --minExpectedThroughput=5 --maxExpectedThroughput=240",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.23 --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=5 --frequency2=6  --minExpectedThroughput=35 --maxExpectedThroughput=280",
+        "wifi-eht-network --simulationTime=0.23s --udp=0 --downlink=1 --useRts=0 --nStations=4 --dlAckType=ACK-SU-FORMAT --enableUlOfdma=1 --enableBsrp=0 --mcs=5 --frequency2=6  --minExpectedThroughput=35 --maxExpectedThroughput=404",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.25 --frequency=2.4 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --frequency2=5 --mpduBufferSize=1024 --minExpectedThroughput=50 --maxExpectedThroughput=120",
+        "wifi-eht-network --simulationTime=0.25s --frequency=2.4 --udp=0 --downlink=1 --useRts=0 --nStations=5 --dlAckType=MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mcs=5 --frequency2=5 --mpduBufferSize=1024 --minExpectedThroughput=50 --maxExpectedThroughput=120",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.3 --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --frequency2=2.4 --minExpectedThroughput=50 --maxExpectedThroughput=140",
+        "wifi-eht-network --simulationTime=0.3s --udp=0 --downlink=1 --useRts=1 --nStations=5 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=0 --mcs=6 --muSchedAccessReqInterval=50ms --frequency2=2.4 --minExpectedThroughput=50 --maxExpectedThroughput=140",
         "True",
         "True",
     ),
     (
-        "wifi-eht-network --simulationTime=0.2 --udp=0 --downlink=0 --useRts=0 --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mpduBufferSize=1024 --mcs=4 --muSchedAccessReqInterval=45ms --frequency2=6 --minExpectedThroughput=50 --maxExpectedThroughput=415",
+        "wifi-eht-network --simulationTime=0.25s --udp=0 --downlink=0 --useRts=0 --nStations=4 --dlAckType=AGGR-MU-BAR --enableUlOfdma=1 --enableBsrp=1 --mpduBufferSize=1024 --mcs=7 --muSchedAccessReqInterval=45ms --frequency2=6 --minExpectedThroughput=70 --maxExpectedThroughput=550",
         "True",
         "True",
     ),
     (
-        "wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=0 --nMpdus=32 --minExpectedThroughput=59 --maxExpectedThroughput=60",
+        "wifi-simple-ht-hidden-stations --simulationTime=1s --enableRts=0 --nMpdus=32 --minExpectedThroughput=59 --maxExpectedThroughput=60",
         "True",
         "True",
     ),
     (
-        "wifi-simple-ht-hidden-stations --simulationTime=1 --enableRts=1 --nMpdus=32 --minExpectedThroughput=57 --maxExpectedThroughput=58",
+        "wifi-simple-ht-hidden-stations --simulationTime=1s --enableRts=1 --nMpdus=32 --minExpectedThroughput=57 --maxExpectedThroughput=58",
         "True",
         "True",
     ),
-    ("wifi-mixed-network --simulationTime=1", "True", "True"),
-    ("wifi-aggregation --simulationTime=1 --verifyResults=1", "True", "True"),
-    ("wifi-txop-aggregation --simulationTime=1 --verifyResults=1", "True", "True"),
-    ("wifi-80211e-txop --simulationTime=1 --verifyResults=1", "True", "True"),
+    ("wifi-mixed-network --simulationTime=1s", "True", "True"),
+    ("wifi-aggregation --simulationTime=1s --verifyResults=1", "True", "True"),
+    ("wifi-txop-aggregation --simulationTime=1s --verifyResults=1", "True", "True"),
+    ("wifi-80211e-txop --simulationTime=1s --verifyResults=1", "True", "True"),
     (
-        "wifi-multi-tos --simulationTime=1 --nWifi=16 --useRts=1 --useShortGuardInterval=1",
+        "wifi-multi-tos --simulationTime=1s --nWifi=16 --useRts=1 --useShortGuardInterval=1",
         "True",
         "True",
     ),
@@ -214,38 +214,38 @@
     ("wifi-hidden-terminal --wifiManager=Rraa", "True", "True"),
     ("wifi-hidden-terminal --wifiManager=Rrpaa", "True", "True"),
     (
-        "wifi-spectrum-per-example --distance=52 --index=3 --wifiType=ns3::SpectrumWifiPhy --simulationTime=1",
+        "wifi-spectrum-per-example --distance=52 --index=3 --wifiType=ns3::SpectrumWifiPhy --simulationTime=1s",
         "True",
         "True",
     ),
     (
-        "wifi-spectrum-per-example --distance=24 --index=31 --wifiType=ns3::YansWifiPhy --simulationTime=1",
+        "wifi-spectrum-per-example --distance=24 --index=31 --wifiType=ns3::YansWifiPhy --simulationTime=1s",
         "True",
         "False",
     ),
     (
-        "wifi-spectrum-per-interference --distance=24 --index=31 --simulationTime=1 --waveformPower=0.1",
+        "wifi-spectrum-per-interference --distance=24 --index=31 --simulationTime=1s --waveformPower=0.1",
         "True",
         "True",
     ),
-    ("wifi-spectrum-saturation-example --simulationTime=1 --index=63", "True", "True"),
+    ("wifi-spectrum-saturation-example --simulationTime=1s --index=63", "True", "True"),
     (
-        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --simulationTime=1",
+        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --simulationTime=1s",
         "True",
         "True",
     ),
     (
-        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --apRaa=Ideal --staRaa=Ideal --simulationTime=1",
+        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211n_5GHZ --apRaa=Ideal --staRaa=Ideal --simulationTime=1s",
         "True",
         "False",
     ),
     (
-        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --simulationTime=1",
+        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --simulationTime=1s",
         "True",
         "False",
     ),
     (
-        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --apRaa=Ideal --staRaa=Ideal --simulationTime=1",
+        "wifi-backward-compatibility --apVersion=80211a --staVersion=80211ac --apRaa=Ideal --staRaa=Ideal --simulationTime=1s",
         "True",
         "False",
     ),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/mixed-wired-wireless.py ns-3.42/examples/wireless/mixed-wired-wireless.py
--- ns-3.41/examples/wireless/mixed-wired-wireless.py	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/mixed-wired-wireless.py	2024-05-29 15:29:46.912073100 -0700
@@ -88,8 +88,8 @@
     #  Simulation defaults are typically set next, before command line
     #  arguments are parsed.
     #
-    ns.core.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.StringValue("1472"))
-    ns.core.Config.SetDefault("ns3::OnOffApplication::DataRate", ns.core.StringValue("100kb/s"))
+    ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.StringValue("1472"))
+    ns.Config.SetDefault("ns3::OnOffApplication::DataRate", ns.StringValue("100kb/s"))
 
     #
     #  For convenience, we add the local variables to the command line argument
@@ -121,29 +121,29 @@
     #  Create a container to manage the nodes of the adhoc(backbone) network.
     #  Later we'll create the rest of the nodes we'll need.
     #
-    backbone = ns.network.NodeContainer()
+    backbone = ns.NodeContainer()
     backbone.Create(backboneNodes.value)
     #
     #  Create the backbone wifi net devices and install them into the nodes in
     #  our container
     #
-    wifi = ns.wifi.WifiHelper()
-    mac = ns.wifi.WifiMacHelper()
+    wifi = ns.WifiHelper()
+    mac = ns.WifiMacHelper()
     mac.SetType("ns3::AdhocWifiMac")
     wifi.SetRemoteStationManager(
-        "ns3::ConstantRateWifiManager", "DataMode", ns.core.StringValue("OfdmRate54Mbps")
+        "ns3::ConstantRateWifiManager", "DataMode", ns.StringValue("OfdmRate54Mbps")
     )
-    wifiPhy = ns.wifi.YansWifiPhyHelper()
+    wifiPhy = ns.YansWifiPhyHelper()
     wifiPhy.SetPcapDataLinkType(wifiPhy.DLT_IEEE802_11_RADIO)
-    wifiChannel = ns.wifi.YansWifiChannelHelper.Default()
+    wifiChannel = ns.YansWifiChannelHelper.Default()
     wifiPhy.SetChannel(wifiChannel.Create())
     backboneDevices = wifi.Install(wifiPhy, mac, backbone)
     #
     #  Add the IPv4 protocol stack to the nodes in our container
     #
     print("Enabling OLSR routing on all backbone nodes")
-    internet = ns.internet.InternetStackHelper()
-    olsr = ns.olsr.OlsrHelper()
+    internet = ns.InternetStackHelper()
+    olsr = ns.OlsrHelper()
     internet.SetRoutingHelper(olsr)
     # has effect on the next Install ()
     internet.Install(backbone)
@@ -153,38 +153,38 @@
     #  Assign IPv4 addresses to the device drivers(actually to the associated
     #  IPv4 interfaces) we just created.
     #
-    ipAddrs = ns.internet.Ipv4AddressHelper()
-    ipAddrs.SetBase(ns.network.Ipv4Address("192.168.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
+    ipAddrs = ns.Ipv4AddressHelper()
+    ipAddrs.SetBase(ns.Ipv4Address("192.168.0.0"), ns.Ipv4Mask("255.255.255.0"))
     ipAddrs.Assign(backboneDevices)
 
     #
     #  The ad-hoc network nodes need a mobility model so we aggregate one to
     #  each of the nodes we just finished building.
     #
-    mobility = ns.mobility.MobilityHelper()
+    mobility = ns.MobilityHelper()
     mobility.SetPositionAllocator(
         "ns3::GridPositionAllocator",
         "MinX",
-        ns.core.DoubleValue(20.0),
+        ns.DoubleValue(20.0),
         "MinY",
-        ns.core.DoubleValue(20.0),
+        ns.DoubleValue(20.0),
         "DeltaX",
-        ns.core.DoubleValue(20.0),
+        ns.DoubleValue(20.0),
         "DeltaY",
-        ns.core.DoubleValue(20.0),
+        ns.DoubleValue(20.0),
         "GridWidth",
-        ns.core.UintegerValue(5),
+        ns.UintegerValue(5),
         "LayoutType",
-        ns.core.StringValue("RowFirst"),
+        ns.StringValue("RowFirst"),
     )
     mobility.SetMobilityModel(
         "ns3::RandomDirection2dMobilityModel",
         "Bounds",
-        ns.mobility.RectangleValue(ns.mobility.Rectangle(-500, 500, -500, 500)),
+        ns.RectangleValue(ns.Rectangle(-500, 500, -500, 500)),
         "Speed",
-        ns.core.StringValue("ns3::ConstantRandomVariable[Constant=2]"),
+        ns.StringValue("ns3::ConstantRandomVariable[Constant=2]"),
         "Pause",
-        ns.core.StringValue("ns3::ConstantRandomVariable[Constant=0.2]"),
+        ns.StringValue("ns3::ConstantRandomVariable[Constant=0.2]"),
     )
     mobility.Install(backbone)
 
@@ -196,7 +196,7 @@
 
     #  Reset the address base-- all of the CSMA networks will be in
     #  the "172.16 address space
-    ipAddrs.SetBase(ns.network.Ipv4Address("172.16.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
+    ipAddrs.SetBase(ns.Ipv4Address("172.16.0.0"), ns.Ipv4Mask("255.255.255.0"))
 
     for i in range(backboneNodes.value):
         print("Configuring local area network for backbone node ", i)
@@ -205,17 +205,17 @@
         #  two containers here; one with all of the new nodes, and one
         #  with all of the nodes including new and existing nodes
         #
-        newLanNodes = ns.network.NodeContainer()
+        newLanNodes = ns.NodeContainer()
         newLanNodes.Create(lanNodes.value - 1)
         #  Now, create the container with all nodes on this link
-        lan = ns.network.NodeContainer(ns.network.NodeContainer(backbone.Get(i)), newLanNodes)
+        lan = ns.NodeContainer(ns.NodeContainer(backbone.Get(i)), newLanNodes)
         #
         #  Create the CSMA net devices and install them into the nodes in our
         #  collection.
         #
-        csma = ns.csma.CsmaHelper()
-        csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000)))
-        csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2)))
+        csma = ns.CsmaHelper()
+        csma.SetChannelAttribute("DataRate", ns.DataRateValue(ns.DataRate(5000000)))
+        csma.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(2)))
         lanDevices = csma.Install(lan)
         #
         #  Add the IPv4 protocol stack to the new LAN nodes
@@ -235,10 +235,10 @@
         # The new LAN nodes need a mobility model so we aggregate one
         # to each of the nodes we just finished building.
         #
-        mobilityLan = ns.mobility.MobilityHelper()
-        positionAlloc = ns.mobility.ListPositionAllocator()
+        mobilityLan = ns.MobilityHelper()
+        positionAlloc = ns.ListPositionAllocator()
         for j in range(newLanNodes.GetN()):
-            positionAlloc.Add(ns.core.Vector(0.0, (j * 10 + 10), 0.0))
+            positionAlloc.Add(ns.Vector(0.0, (j * 10 + 10), 0.0))
 
         mobilityLan.SetPositionAllocator(positionAlloc)
         mobilityLan.PushReferenceMobilityModel(backbone.Get(i))
@@ -253,7 +253,7 @@
 
     #  Reset the address base-- all of the 802.11 networks will be in
     #  the "10.0" address space
-    ipAddrs.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
+    ipAddrs.SetBase(ns.Ipv4Address("10.0.0.0"), ns.Ipv4Mask("255.255.255.0"))
     tempRef = []  # list of references to be held to prevent garbage collection
     for i in range(backboneNodes.value):
         print("Configuring wireless network for backbone node ", i)
@@ -262,26 +262,26 @@
         #  two containers here; one with all of the new nodes, and one
         #  with all of the nodes including new and existing nodes
         #
-        stas = ns.network.NodeContainer()
+        stas = ns.NodeContainer()
         stas.Create(infraNodes.value - 1)
         #  Now, create the container with all nodes on this link
-        infra = ns.network.NodeContainer(ns.network.NodeContainer(backbone.Get(i)), stas)
+        infra = ns.NodeContainer(ns.NodeContainer(backbone.Get(i)), stas)
         #
         #  Create another ad hoc network and devices
         #
-        ssid = ns.wifi.Ssid("wifi-infra" + str(i))
-        wifiInfra = ns.wifi.WifiHelper()
+        ssid = ns.Ssid("wifi-infra" + str(i))
+        wifiInfra = ns.WifiHelper()
         wifiPhy.SetChannel(wifiChannel.Create())
-        macInfra = ns.wifi.WifiMacHelper()
-        macInfra.SetType("ns3::StaWifiMac", "Ssid", ns.wifi.SsidValue(ssid))
+        macInfra = ns.WifiMacHelper()
+        macInfra.SetType("ns3::StaWifiMac", "Ssid", ns.SsidValue(ssid))
 
         # setup stas
         staDevices = wifiInfra.Install(wifiPhy, macInfra, stas)
         # setup ap.
-        macInfra.SetType("ns3::ApWifiMac", "Ssid", ns.wifi.SsidValue(ssid))
+        macInfra.SetType("ns3::ApWifiMac", "Ssid", ns.SsidValue(ssid))
         apDevices = wifiInfra.Install(wifiPhy, macInfra, backbone.Get(i))
         # Collect all of these new devices
-        infraDevices = ns.network.NetDeviceContainer(apDevices, staDevices)
+        infraDevices = ns.NetDeviceContainer(apDevices, staDevices)
 
         #  Add the IPv4 protocol stack to the nodes in our container
         #
@@ -299,7 +299,7 @@
 
         # This call returns an instance that needs to be stored in the outer scope
         # not to be garbage collected when overwritten in the next iteration
-        subnetAlloc = ns.mobility.ListPositionAllocator()
+        subnetAlloc = ns.ListPositionAllocator()
 
         # Appending the object to a list is enough to prevent the garbage collection
         tempRef.append(subnetAlloc)
@@ -309,18 +309,18 @@
         #  to each of the nodes we just finished building.
         #
         for j in range(infra.GetN()):
-            subnetAlloc.Add(ns.core.Vector(0.0, j, 0.0))
+            subnetAlloc.Add(ns.Vector(0.0, j, 0.0))
 
         mobility.PushReferenceMobilityModel(backbone.Get(i))
         mobility.SetPositionAllocator(subnetAlloc)
         mobility.SetMobilityModel(
             "ns3::RandomDirection2dMobilityModel",
             "Bounds",
-            ns.mobility.RectangleValue(ns.mobility.Rectangle(-10, 10, -10, 10)),
+            ns.RectangleValue(ns.Rectangle(-10, 10, -10, 10)),
             "Speed",
-            ns.core.StringValue("ns3::ConstantRandomVariable[Constant=3]"),
+            ns.StringValue("ns3::ConstantRandomVariable[Constant=3]"),
             "Pause",
-            ns.core.StringValue("ns3::ConstantRandomVariable[Constant=0.4]"),
+            ns.StringValue("ns3::ConstantRandomVariable[Constant=0.4]"),
         )
         mobility.Install(stas)
 
@@ -335,14 +335,14 @@
     print("Create Applications.")
     port = 9  #  Discard port(RFC 863)
 
-    appSource = ns.network.NodeList.GetNode(backboneNodes.value)
+    appSource = ns.NodeList.GetNode(backboneNodes.value)
     lastNodeIndex = (
         backboneNodes.value
         + backboneNodes.value * (lanNodes.value - 1)
         + backboneNodes.value * (infraNodes.value - 1)
         - 1
     )
-    appSink = ns.network.NodeList.GetNode(lastNodeIndex)
+    appSink = ns.NodeList.GetNode(lastNodeIndex)
 
     ns.cppyy.cppdef(
         """
@@ -353,22 +353,20 @@
     )
     # Let's fetch the IP address of the last node, which is on Ipv4Interface 1
     remoteAddr = ns.cppyy.gbl.getIpv4AddressFromNode(appSink)
-    socketAddr = ns.network.InetSocketAddress(remoteAddr, port)
-    onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", socketAddr.ConvertTo())
-    apps = onoff.Install(ns.network.NodeContainer(appSource))
-    apps.Start(ns.core.Seconds(3))
-    apps.Stop(ns.core.Seconds(stopTime.value - 1))
+    socketAddr = ns.InetSocketAddress(remoteAddr, port)
+    onoff = ns.OnOffHelper("ns3::UdpSocketFactory", socketAddr.ConvertTo())
+    apps = onoff.Install(ns.NodeContainer(appSource))
+    apps.Start(ns.Seconds(3))
+    apps.Stop(ns.Seconds(stopTime.value - 1))
 
     #  Create a packet sink to receive these packets
-    sink = ns.applications.PacketSinkHelper(
+    sink = ns.PacketSinkHelper(
         "ns3::UdpSocketFactory",
-        ns.network.InetSocketAddress(
-            ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)
-        ).ConvertTo(),
+        ns.InetSocketAddress(ns.InetSocketAddress(ns.Ipv4Address.GetAny(), port)).ConvertTo(),
     )
-    sinkContainer = ns.network.NodeContainer(appSink)
+    sinkContainer = ns.NodeContainer(appSink)
     apps = sink.Install(sinkContainer)
-    apps.Start(ns.core.Seconds(3))
+    apps.Start(ns.Seconds(3))
 
     # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # /
     #                                                                        #
@@ -377,11 +375,11 @@
     # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # /
 
     print("Configure Tracing.")
-    csma = ns.csma.CsmaHelper()
+    csma = ns.CsmaHelper()
     #
     #  Let's set up some ns-2-like ascii traces, using another helper class
     #
-    ascii = ns.network.AsciiTraceHelper()
+    ascii = ns.AsciiTraceHelper()
     stream = ascii.CreateFileStream("mixed-wireless.tr")
     wifiPhy.EnableAsciiAll(stream)
     csma.EnableAsciiAll(stream)
@@ -405,9 +403,9 @@
     # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
     print("Run Simulation.")
-    ns.core.Simulator.Stop(ns.core.Seconds(stopTime.value))
-    ns.core.Simulator.Run()
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Stop(ns.Seconds(stopTime.value))
+    ns.Simulator.Run()
+    ns.Simulator.Destroy()
 
 
 if __name__ == "__main__":
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-80211e-txop.cc ns-3.42/examples/wireless/wifi-80211e-txop.cc
--- ns-3.41/examples/wireless/wifi-80211e-txop.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-80211e-txop.cc	2024-05-29 15:29:46.912073100 -0700
@@ -55,7 +55,7 @@
 //
 // The user can select the distance between the stations and the APs, can enable/disable the RTS/CTS
 // mechanism and can choose the payload size and the simulation duration. Example: ./ns3 run
-// "wifi-80211e-txop --distance=10 --simulationTime=20 --payloadSize=1000"
+// "wifi-80211e-txop --distance=10 --simulationTime=20s --payloadSize=1000"
 //
 // The output prints the throughput measured for the 4 cases/networks described above. When TXOP is
 // enabled, results show increased throughput since the channel is granted for a longer duration.
@@ -94,16 +94,16 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t payloadSize = 1472; // bytes
-    double simulationTime = 10;  // seconds
-    double distance = 5;         // meters
-    bool enablePcap = false;
-    bool verifyResults = false; // used for regression
-    Time txopLimit = MicroSeconds(4096);
+    uint32_t payloadSize{1472}; // bytes
+    Time simulationTime{"10s"};
+    double distance{5}; // meters
+    bool enablePcap{false};
+    bool verifyResults{false}; // used for regression
+    Time txopLimit{"4096us"};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
@@ -296,74 +296,74 @@
     UdpServerHelper serverA(port);
     ApplicationContainer serverAppA = serverA.Install(wifiApNodes.Get(0));
     serverAppA.Start(Seconds(0.0));
-    serverAppA.Stop(Seconds(simulationTime + 1));
+    serverAppA.Stop(simulationTime + Seconds(1.0));
 
     InetSocketAddress destA(ApInterfaceA.GetAddress(0), port);
-    destA.SetTos(0x70); // AC_BE
 
     OnOffHelper clientA("ns3::UdpSocketFactory", destA);
     clientA.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
     clientA.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
     clientA.SetAttribute("DataRate", StringValue("100000kb/s"));
     clientA.SetAttribute("PacketSize", UintegerValue(payloadSize));
+    clientA.SetAttribute("Tos", UintegerValue(0x70)); // AC_BE
 
     ApplicationContainer clientAppA = clientA.Install(wifiStaNodes.Get(0));
     clientAppA.Start(Seconds(1.0));
-    clientAppA.Stop(Seconds(simulationTime + 1));
+    clientAppA.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverB(port);
     ApplicationContainer serverAppB = serverB.Install(wifiApNodes.Get(1));
     serverAppB.Start(Seconds(0.0));
-    serverAppB.Stop(Seconds(simulationTime + 1));
+    serverAppB.Stop(simulationTime + Seconds(1.0));
 
     InetSocketAddress destB(ApInterfaceB.GetAddress(0), port);
-    destB.SetTos(0x70); // AC_BE
 
     OnOffHelper clientB("ns3::UdpSocketFactory", destB);
     clientB.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
     clientB.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
     clientB.SetAttribute("DataRate", StringValue("100000kb/s"));
     clientB.SetAttribute("PacketSize", UintegerValue(payloadSize));
+    clientB.SetAttribute("Tos", UintegerValue(0x70)); // AC_BE
 
     ApplicationContainer clientAppB = clientB.Install(wifiStaNodes.Get(1));
     clientAppB.Start(Seconds(1.0));
-    clientAppB.Stop(Seconds(simulationTime + 1));
+    clientAppB.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverC(port);
     ApplicationContainer serverAppC = serverC.Install(wifiApNodes.Get(2));
     serverAppC.Start(Seconds(0.0));
-    serverAppC.Stop(Seconds(simulationTime + 1));
+    serverAppC.Stop(simulationTime + Seconds(1.0));
 
     InetSocketAddress destC(ApInterfaceC.GetAddress(0), port);
-    destC.SetTos(0xb8); // AC_VI
 
     OnOffHelper clientC("ns3::UdpSocketFactory", destC);
     clientC.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
     clientC.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
     clientC.SetAttribute("DataRate", StringValue("100000kb/s"));
     clientC.SetAttribute("PacketSize", UintegerValue(payloadSize));
+    clientC.SetAttribute("Tos", UintegerValue(0xb8)); // AC_VI
 
     ApplicationContainer clientAppC = clientC.Install(wifiStaNodes.Get(2));
     clientAppC.Start(Seconds(1.0));
-    clientAppC.Stop(Seconds(simulationTime + 1));
+    clientAppC.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverD(port);
     ApplicationContainer serverAppD = serverD.Install(wifiApNodes.Get(3));
     serverAppD.Start(Seconds(0.0));
-    serverAppD.Stop(Seconds(simulationTime + 1));
+    serverAppD.Stop(simulationTime + Seconds(1.0));
 
     InetSocketAddress destD(ApInterfaceD.GetAddress(0), port);
-    destD.SetTos(0xb8); // AC_VI
 
     OnOffHelper clientD("ns3::UdpSocketFactory", destD);
     clientD.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
     clientD.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
     clientD.SetAttribute("DataRate", StringValue("100000kb/s"));
     clientD.SetAttribute("PacketSize", UintegerValue(payloadSize));
+    clientD.SetAttribute("Tos", UintegerValue(0xb8)); // AC_VI
 
     ApplicationContainer clientAppD = clientD.Install(wifiStaNodes.Get(3));
     clientAppD.Start(Seconds(1.0));
-    clientAppD.Stop(Seconds(simulationTime + 1));
+    clientAppD.Stop(simulationTime + Seconds(1.0));
 
     if (enablePcap)
     {
@@ -377,18 +377,18 @@
         phy.EnablePcap("STA_D", staDeviceD.Get(0));
     }
 
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
     /* Show results */
-    uint64_t totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
+    double totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
+    double totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
+    double totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
+    double totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
 
     Simulator::Destroy();
 
-    double throughput = totalPacketsThroughA * payloadSize * 8 / (simulationTime * 1000000.0);
+    auto throughput = totalPacketsThroughA * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "AC_BE with default TXOP limit (0ms): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 28 || throughput > 29))
@@ -397,7 +397,7 @@
         exit(1);
     }
 
-    throughput = totalPacketsThroughB * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughB * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "AC_BE with non-default TXOP limit (4.096ms): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 36.5 || throughput > 37))
@@ -415,7 +415,7 @@
         exit(1);
     }
 
-    throughput = totalPacketsThroughC * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughC * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "AC_VI with default TXOP limit (4.096ms): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 36.5 || throughput > 37.5))
@@ -433,7 +433,7 @@
         exit(1);
     }
 
-    throughput = totalPacketsThroughD * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughD * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "AC_VI with non-default TXOP limit (0ms): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 31.5 || throughput > 32.5))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-80211n-mimo.cc ns-3.42/examples/wireless/wifi-80211n-mimo.cc
--- ns-3.41/examples/wireless/wifi-80211n-mimo.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-80211n-mimo.cc	2024-05-29 15:29:46.912073100 -0700
@@ -41,6 +41,7 @@
 #include "ns3/config.h"
 #include "ns3/double.h"
 #include "ns3/gnuplot.h"
+#include "ns3/ht-phy.h"
 #include "ns3/internet-stack-helper.h"
 #include "ns3/ipv4-address-helper.h"
 #include "ns3/ipv4-global-routing-helper.h"
@@ -70,17 +71,17 @@
         "HtMcs24", "HtMcs25", "HtMcs26", "HtMcs27", "HtMcs28", "HtMcs29", "HtMcs30", "HtMcs31",
     };
 
-    bool udp = true;
-    double simulationTime = 5; // seconds
-    double frequency = 5.0;    // whether 2.4 or 5.0 GHz
-    double step = 5;           // meters
-    bool shortGuardInterval = false;
-    bool channelBonding = false;
-    bool preambleDetection = true;
+    bool udp{true};
+    Time simulationTime{"5s"};
+    double frequency{5.0}; // whether 2.4 or 5.0 GHz
+    double step{5};        // meters
+    bool shortGuardInterval{false};
+    bool channelBonding{false};
+    bool preambleDetection{true};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("step", "Granularity of the results to be plotted in meters", step);
-    cmd.AddValue("simulationTime", "Simulation time per step (in seconds)", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time per step", simulationTime);
     cmd.AddValue("channelBonding",
                  "Enable/disable channel bonding (channel width = 20 MHz if false, channel width = "
                  "40 MHz if true)",
@@ -213,6 +214,10 @@
             apNodeInterface = address.Assign(apDevice);
 
             /* Setting applications */
+            const auto maxLoad = HtPhy::GetDataRate(i,
+                                                    channelBonding ? 40 : 20,
+                                                    shortGuardInterval ? 400 : 800,
+                                                    nStreams);
             ApplicationContainer serverApp;
             if (udp)
             {
@@ -221,15 +226,16 @@
                 UdpServerHelper server(port);
                 serverApp = server.Install(wifiStaNode.Get(0));
                 serverApp.Start(Seconds(0.0));
-                serverApp.Stop(Seconds(simulationTime + 1));
+                serverApp.Stop(simulationTime + Seconds(1.0));
+                const auto packetInterval = payloadSize * 8.0 / maxLoad;
 
                 UdpClientHelper client(staNodeInterface.GetAddress(0), port);
                 client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-                client.SetAttribute("Interval", TimeValue(Time("0.00001"))); // packets/s
+                client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
                 client.SetAttribute("PacketSize", UintegerValue(payloadSize));
                 ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
                 clientApp.Start(Seconds(1.0));
-                clientApp.Stop(Seconds(simulationTime + 1));
+                clientApp.Stop(simulationTime + Seconds(1.0));
             }
             else
             {
@@ -239,7 +245,7 @@
                 PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
                 serverApp = packetSinkHelper.Install(wifiStaNode.Get(0));
                 serverApp.Start(Seconds(0.0));
-                serverApp.Stop(Seconds(simulationTime + 1));
+                serverApp.Stop(simulationTime + Seconds(1.0));
 
                 OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny());
                 onoff.SetAttribute("OnTime",
@@ -247,34 +253,34 @@
                 onoff.SetAttribute("OffTime",
                                    StringValue("ns3::ConstantRandomVariable[Constant=0]"));
                 onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-                onoff.SetAttribute("DataRate", DataRateValue(1000000000)); // bit/s
+                onoff.SetAttribute("DataRate", DataRateValue(maxLoad));
                 AddressValue remoteAddress(InetSocketAddress(staNodeInterface.GetAddress(0), port));
                 onoff.SetAttribute("Remote", remoteAddress);
                 ApplicationContainer clientApp = onoff.Install(wifiApNode.Get(0));
                 clientApp.Start(Seconds(1.0));
-                clientApp.Stop(Seconds(simulationTime + 1));
+                clientApp.Stop(simulationTime + Seconds(1.0));
             }
 
             Ipv4GlobalRoutingHelper::PopulateRoutingTables();
 
-            Simulator::Stop(Seconds(simulationTime + 1));
+            Simulator::Stop(simulationTime + Seconds(1.0));
             Simulator::Run();
 
             double throughput = 0;
             if (udp)
             {
                 // UDP
-                uint64_t totalPacketsThrough =
+                double totalPacketsThrough =
                     DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
-                throughput =
-                    totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0); // Mbit/s
+                throughput = totalPacketsThrough * payloadSize * 8 /
+                             simulationTime.GetMicroSeconds(); // Mbit/s
             }
             else
             {
                 // TCP
-                uint64_t totalPacketsThrough =
+                double totalPacketsThrough =
                     DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
-                throughput = totalPacketsThrough * 8 / (simulationTime * 1000000.0); // Mbit/s
+                throughput = totalPacketsThrough * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
             }
             dataset.Add(d, throughput);
             std::cout << throughput << " Mbit/s" << std::endl;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-aggregation.cc ns-3.42/examples/wireless/wifi-aggregation.cc
--- ns-3.41/examples/wireless/wifi-aggregation.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-aggregation.cc	2024-05-29 15:29:46.912073100 -0700
@@ -59,7 +59,7 @@
 //
 // The user can select the distance between the stations and the APs and can enable/disable the
 // RTS/CTS mechanism. Example: ./ns3 run "wifi-aggregation --distance=10 --enableRts=0
-// --simulationTime=20"
+// --simulationTime=20s"
 //
 // The output prints the throughput measured for the 4 cases/networks described above. When default
 // aggregation parameters are enabled, the maximum A-MPDU size is 65 kB and the throughput is
@@ -82,17 +82,17 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t payloadSize = 1472; // bytes
-    double simulationTime = 10;  // seconds
-    double distance = 5;         // meters
-    bool enableRts = false;
-    bool enablePcap = false;
-    bool verifyResults = false; // used for regression
+    uint32_t payloadSize{1472}; // bytes
+    Time simulationTime{"10s"};
+    double distance{5}; // meters
+    bool enableRts{false};
+    bool enablePcap{false};
+    bool verifyResults{false}; // used for regression
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
     cmd.AddValue("enableRts", "Enable or disable RTS/CTS", enableRts);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
@@ -282,7 +282,7 @@
     UdpServerHelper serverA(port);
     ApplicationContainer serverAppA = serverA.Install(wifiStaNodes.Get(0));
     serverAppA.Start(Seconds(0.0));
-    serverAppA.Stop(Seconds(simulationTime + 1));
+    serverAppA.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientA(StaInterfaceA.GetAddress(0), port);
     clientA.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -291,12 +291,12 @@
 
     ApplicationContainer clientAppA = clientA.Install(wifiApNodes.Get(0));
     clientAppA.Start(Seconds(1.0));
-    clientAppA.Stop(Seconds(simulationTime + 1));
+    clientAppA.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverB(port);
     ApplicationContainer serverAppB = serverB.Install(wifiStaNodes.Get(1));
     serverAppB.Start(Seconds(0.0));
-    serverAppB.Stop(Seconds(simulationTime + 1));
+    serverAppB.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientB(StaInterfaceB.GetAddress(0), port);
     clientB.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -305,12 +305,12 @@
 
     ApplicationContainer clientAppB = clientB.Install(wifiApNodes.Get(1));
     clientAppB.Start(Seconds(1.0));
-    clientAppB.Stop(Seconds(simulationTime + 1));
+    clientAppB.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverC(port);
     ApplicationContainer serverAppC = serverC.Install(wifiStaNodes.Get(2));
     serverAppC.Start(Seconds(0.0));
-    serverAppC.Stop(Seconds(simulationTime + 1));
+    serverAppC.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientC(StaInterfaceC.GetAddress(0), port);
     clientC.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -319,12 +319,12 @@
 
     ApplicationContainer clientAppC = clientC.Install(wifiApNodes.Get(2));
     clientAppC.Start(Seconds(1.0));
-    clientAppC.Stop(Seconds(simulationTime + 1));
+    clientAppC.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverD(port);
     ApplicationContainer serverAppD = serverD.Install(wifiStaNodes.Get(3));
     serverAppD.Start(Seconds(0.0));
-    serverAppD.Stop(Seconds(simulationTime + 1));
+    serverAppD.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientD(StaInterfaceD.GetAddress(0), port);
     clientD.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -333,7 +333,7 @@
 
     ApplicationContainer clientAppD = clientD.Install(wifiApNodes.Get(3));
     clientAppD.Start(Seconds(1.0));
-    clientAppD.Stop(Seconds(simulationTime + 1));
+    clientAppD.Stop(simulationTime + Seconds(1.0));
 
     if (enablePcap)
     {
@@ -347,18 +347,18 @@
         phy.EnablePcap("STA_D", staDeviceD.Get(0));
     }
 
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
     // Show results
-    uint64_t totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
+    double totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
+    double totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
+    double totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
+    double totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
 
     Simulator::Destroy();
 
-    double throughput = totalPacketsThroughA * payloadSize * 8 / (simulationTime * 1000000.0);
+    auto throughput = totalPacketsThroughA * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Throughput with default configuration (A-MPDU aggregation enabled, 65kB): "
               << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 59.0 || throughput > 60.0))
@@ -367,7 +367,7 @@
         exit(1);
     }
 
-    throughput = totalPacketsThroughB * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughB * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Throughput with aggregation disabled: " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 30 || throughput > 31))
     {
@@ -375,7 +375,7 @@
         exit(1);
     }
 
-    throughput = totalPacketsThroughC * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughC * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Throughput with A-MPDU disabled and A-MSDU enabled (8kB): " << throughput
               << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 51 || throughput > 52))
@@ -384,7 +384,7 @@
         exit(1);
     }
 
-    throughput = totalPacketsThroughD * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughD * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Throughput with A-MPDU enabled (32kB) and A-MSDU enabled (4kB): " << throughput
               << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 58 || throughput > 59))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-ap.py ns-3.42/examples/wireless/wifi-ap.py
--- ns-3.41/examples/wireless/wifi-ap.py	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-ap.py	2024-05-29 15:29:46.912073100 -0700
@@ -93,16 +93,16 @@
 
 
 def main(argv):
-    ns.core.CommandLine().Parse(argv)
+    ns.CommandLine().Parse(argv)
 
-    ns.network.Packet.EnablePrinting()
+    ns.Packet.EnablePrinting()
 
-    wifi = ns.wifi.WifiHelper()
-    mobility = ns.mobility.MobilityHelper()
-    stas = ns.network.NodeContainer()
-    ap = ns.network.NodeContainer()
+    wifi = ns.WifiHelper()
+    mobility = ns.MobilityHelper()
+    stas = ns.NodeContainer()
+    ap = ns.NodeContainer()
     # NetDeviceContainer staDevs;
-    packetSocket = ns.network.PacketSocketHelper()
+    packetSocket = ns.PacketSocketHelper()
 
     stas.Create(2)
     ap.Create(1)
@@ -111,45 +111,45 @@
     packetSocket.Install(stas)
     packetSocket.Install(ap)
 
-    wifiPhy = ns.wifi.YansWifiPhyHelper()
-    wifiChannel = ns.wifi.YansWifiChannelHelper.Default()
+    wifiPhy = ns.YansWifiPhyHelper()
+    wifiChannel = ns.YansWifiChannelHelper.Default()
     wifiPhy.SetChannel(wifiChannel.Create())
 
-    ssid = ns.wifi.Ssid("wifi-default")
-    wifiMac = ns.wifi.WifiMacHelper()
+    ssid = ns.Ssid("wifi-default")
+    wifiMac = ns.WifiMacHelper()
 
     # setup stas.
     wifiMac.SetType(
         "ns3::StaWifiMac",
         "ActiveProbing",
-        ns.core.BooleanValue(True),
+        ns.BooleanValue(True),
         "Ssid",
-        ns.wifi.SsidValue(ssid),
+        ns.SsidValue(ssid),
     )
     staDevs = wifi.Install(wifiPhy, wifiMac, stas)
     # setup ap.
-    wifiMac.SetType("ns3::ApWifiMac", "Ssid", ns.wifi.SsidValue(ssid))
+    wifiMac.SetType("ns3::ApWifiMac", "Ssid", ns.SsidValue(ssid))
     wifi.Install(wifiPhy, wifiMac, ap)
 
     # mobility.
     mobility.Install(stas)
     mobility.Install(ap)
 
-    ns.core.Simulator.Schedule(ns.core.Seconds(1.0), ns.cppyy.gbl.AdvancePosition, ap.Get(0))
+    ns.Simulator.Schedule(ns.Seconds(1.0), ns.cppyy.gbl.AdvancePosition, ap.Get(0))
 
-    socket = ns.network.PacketSocketAddress()
+    socket = ns.PacketSocketAddress()
     socket.SetSingleDevice(staDevs.Get(0).GetIfIndex())
     socket.SetPhysicalAddress(staDevs.Get(1).GetAddress())
     socket.SetProtocol(1)
 
-    onoff = ns.applications.OnOffHelper("ns3::PacketSocketFactory", socket.ConvertTo())
-    onoff.SetConstantRate(ns.network.DataRate("500kb/s"))
+    onoff = ns.OnOffHelper("ns3::PacketSocketFactory", socket.ConvertTo())
+    onoff.SetConstantRate(ns.DataRate("500kb/s"))
 
-    apps = onoff.Install(ns.network.NodeContainer(stas.Get(0)))
-    apps.Start(ns.core.Seconds(0.5))
-    apps.Stop(ns.core.Seconds(43.0))
+    apps = onoff.Install(ns.NodeContainer(stas.Get(0)))
+    apps.Start(ns.Seconds(0.5))
+    apps.Stop(ns.Seconds(43.0))
 
-    ns.core.Simulator.Stop(ns.core.Seconds(44.0))
+    ns.Simulator.Stop(ns.Seconds(44.0))
 
     #   Config::Connect("/NodeList/*/DeviceList/*/Tx", MakeCallback(&DevTxTrace));
     #   Config::Connect("/NodeList/*/DeviceList/*/Rx", MakeCallback(&DevRxTrace));
@@ -158,8 +158,8 @@
     #   Config::Connect("/NodeList/*/DeviceList/*/Phy/Tx", MakeCallback(&PhyTxTrace));
     #   Config::Connect("/NodeList/*/DeviceList/*/Phy/State", MakeCallback(&PhyStateTrace));
 
-    ns.core.Simulator.Run()
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Run()
+    ns.Simulator.Destroy()
 
     return 0
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-backward-compatibility.cc ns-3.42/examples/wireless/wifi-backward-compatibility.cc
--- ns-3.41/examples/wireless/wifi-backward-compatibility.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-backward-compatibility.cc	2024-05-29 15:29:46.912073100 -0700
@@ -113,17 +113,17 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t payloadSize = 1472; // bytes
-    double simulationTime = 10;  // seconds
-    std::string apVersion = "80211a";
-    std::string staVersion = "80211n_5GHZ";
-    std::string apRaa = "Minstrel";
-    std::string staRaa = "MinstrelHt";
-    bool apHasTraffic = false;
-    bool staHasTraffic = true;
+    uint32_t payloadSize{1472}; // bytes
+    Time simulationTime{"10s"};
+    std::string apVersion{"80211a"};
+    std::string staVersion{"80211n_5GHZ"};
+    std::string apRaa{"Minstrel"};
+    std::string staRaa{"MinstrelHt"};
+    bool apHasTraffic{false};
+    bool staHasTraffic{true};
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("apVersion",
                  "The standard version used by the AP: 80211a, 80211b, 80211g, 80211p, "
                  "80211n_2_4GHZ, 80211n_5GHZ, 80211ac, 80211ax_2_4GHZ or 80211ax_5GHZ",
@@ -204,12 +204,12 @@
     UdpServerHelper apServer(9);
     ApplicationContainer apServerApp = apServer.Install(wifiApNode.Get(0));
     apServerApp.Start(Seconds(0.0));
-    apServerApp.Stop(Seconds(simulationTime + 1));
+    apServerApp.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper staServer(5001);
     ApplicationContainer staServerApp = staServer.Install(wifiStaNode.Get(0));
     staServerApp.Start(Seconds(0.0));
-    staServerApp.Stop(Seconds(simulationTime + 1));
+    staServerApp.Stop(simulationTime + Seconds(1.0));
 
     if (apHasTraffic)
     {
@@ -219,7 +219,7 @@
         apClient.SetAttribute("PacketSize", UintegerValue(payloadSize)); // bytes
         ApplicationContainer apClientApp = apClient.Install(wifiApNode.Get(0));
         apClientApp.Start(Seconds(1.0));
-        apClientApp.Stop(Seconds(simulationTime + 1));
+        apClientApp.Stop(simulationTime + Seconds(1.0));
     }
 
     if (staHasTraffic)
@@ -230,21 +230,21 @@
         staClient.SetAttribute("PacketSize", UintegerValue(payloadSize)); // bytes
         ApplicationContainer staClientApp = staClient.Install(wifiStaNode.Get(0));
         staClientApp.Start(Seconds(1.0));
-        staClientApp.Stop(Seconds(simulationTime + 1));
+        staClientApp.Stop(simulationTime + Seconds(1.0));
     }
 
     Ipv4GlobalRoutingHelper::PopulateRoutingTables();
 
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
-    uint64_t rxBytes;
+    double rxBytes;
     double throughput;
     bool error = false;
     if (apHasTraffic)
     {
         rxBytes = payloadSize * DynamicCast<UdpServer>(staServerApp.Get(0))->GetReceived();
-        throughput = (rxBytes * 8) / (simulationTime * 1000000.0); // Mbit/s
+        throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds(); // Mbit/s
         std::cout << "AP Throughput: " << throughput << " Mbit/s" << std::endl;
         if (throughput == 0)
         {
@@ -254,7 +254,7 @@
     if (staHasTraffic)
     {
         rxBytes = payloadSize * DynamicCast<UdpServer>(apServerApp.Get(0))->GetReceived();
-        throughput = (rxBytes * 8) / (simulationTime * 1000000.0); // Mbit/s
+        throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds(); // Mbit/s
         std::cout << "STA Throughput: " << throughput << " Mbit/s" << std::endl;
         if (throughput == 0)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-eht-network.cc ns-3.42/examples/wireless/wifi-eht-network.cc
--- ns-3.41/examples/wireless/wifi-eht-network.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-eht-network.cc	2024-05-29 15:29:46.912073100 -0700
@@ -31,7 +31,6 @@
 #include "ns3/on-off-helper.h"
 #include "ns3/packet-sink-helper.h"
 #include "ns3/packet-sink.h"
-#include "ns3/rng-seed-manager.h"
 #include "ns3/spectrum-wifi-helper.h"
 #include "ns3/ssid.h"
 #include "ns3/string.h"
@@ -110,7 +109,7 @@
                       const ApplicationContainer& serverApp,
                       uint32_t payloadSize,
                       Time tputInterval,
-                      double simulationTime)
+                      Time simulationTime)
 {
     auto newRxBytes = GetRxBytes(udp, serverApp, payloadSize);
     Time now = Simulator::Now();
@@ -127,9 +126,9 @@
 
     rxBytes.swap(newRxBytes);
 
-    if (now < Seconds(simulationTime) - NanoSeconds(1))
+    if (now < (simulationTime - NanoSeconds(1)))
     {
-        Simulator::Schedule(Min(tputInterval, Seconds(simulationTime) - now - NanoSeconds(1)),
+        Simulator::Schedule(Min(tputInterval, simulationTime - now - NanoSeconds(1)),
                             &PrintIntermediateTput,
                             rxBytes,
                             udp,
@@ -152,9 +151,11 @@
     uint16_t transitionDelayUsec{128};
     uint16_t channelSwitchDelayUsec{100};
     bool switchAuxPhy{true};
-    double simulationTime{10}; // seconds
-    double distance{1.0};      // meters
-    double frequency{5};       // whether the first link operates in the 2.4, 5 or 6 GHz
+    uint16_t auxPhyChWidth{20};
+    bool auxPhyTxCapable{true};
+    Time simulationTime{"10s"};
+    double distance{1.0}; // meters
+    double frequency{5};  // whether the first link operates in the 2.4, 5 or 6 GHz
     double frequency2{0}; // whether the second link operates in the 2.4, 5 or 6 GHz (0 means no
                           // second link exists)
     double frequency3{
@@ -199,13 +200,19 @@
                  "Whether Aux PHY should switch channel to operate on the link on which "
                  "the Main PHY was operating before moving to the link of the Aux PHY. ",
                  switchAuxPhy);
+    cmd.AddValue("emlsrAuxChWidth",
+                 "The maximum channel width (MHz) supported by Aux PHYs.",
+                 auxPhyChWidth);
+    cmd.AddValue("emlsrAuxTxCapable",
+                 "Whether Aux PHYs are capable of transmitting.",
+                 auxPhyTxCapable);
     cmd.AddValue("channelSwitchDelay",
                  "The PHY channel switch delay in microseconds",
                  channelSwitchDelayUsec);
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("udp", "UDP if set to 1, TCP otherwise", udp);
     cmd.AddValue("downlink",
                  "Generate downlink flows if set to 1, uplink flows otherwise",
@@ -214,7 +221,7 @@
     cmd.AddValue("mpduBufferSize",
                  "Size (in number of MPDUs) of the BlockAck buffer",
                  mpduBufferSize);
-    cmd.AddValue("nStations", "Number of non-AP HE stations", nStations);
+    cmd.AddValue("nStations", "Number of non-AP EHT stations", nStations);
     cmd.AddValue("dlAckType",
                  "Ack sequence type for DL OFDMA (NO-OFDMA, ACK-SU-FORMAT, MU-BAR, AGGR-MU-BAR)",
                  dlAckSeqType);
@@ -288,9 +295,10 @@
         double previous = 0;
         uint16_t maxChannelWidth =
             (frequency != 2.4 && frequency2 != 2.4 && frequency3 != 2.4) ? 160 : 40;
+        int minGi = enableUlOfdma ? 1600 : 800;
         for (int channelWidth = 20; channelWidth <= maxChannelWidth;) // MHz
         {
-            for (int gi = 3200; gi >= 800;) // Nanoseconds
+            for (int gi = 3200; gi >= minGi;) // Nanoseconds
             {
                 if (!udp)
                 {
@@ -318,8 +326,7 @@
                 if (frequency2 == frequency || frequency3 == frequency ||
                     (frequency3 != 0 && frequency3 == frequency2))
                 {
-                    std::cout << "Frequency values must be unique!" << std::endl;
-                    return 0;
+                    NS_FATAL_ERROR("Frequency values must be unique!");
                 }
 
                 for (auto freq : {frequency, frequency2, frequency3})
@@ -370,8 +377,7 @@
                     }
                     else
                     {
-                        std::cout << "Wrong frequency value!" << std::endl;
-                        return 0;
+                        NS_FATAL_ERROR("Wrong frequency value!");
                     }
                     nLinks++;
                 }
@@ -402,7 +408,11 @@
                                     "EmlsrTransitionDelay",
                                     TimeValue(MicroSeconds(transitionDelayUsec)),
                                     "SwitchAuxPhy",
-                                    BooleanValue(switchAuxPhy));
+                                    BooleanValue(switchAuxPhy),
+                                    "AuxPhyTxCapable",
+                                    BooleanValue(auxPhyTxCapable),
+                                    "AuxPhyChannelWidth",
+                                    UintegerValue(auxPhyChWidth));
                 for (uint8_t linkId = 0; linkId < nLinks; linkId++)
                 {
                     phy.Set(linkId, "ChannelSettings", StringValue(channelStr[linkId]));
@@ -431,8 +441,6 @@
                             SsidValue(ssid));
                 apDevice = wifi.Install(phy, mac, wifiApNode);
 
-                RngSeedManager::SetSeed(1);
-                RngSeedManager::SetRun(1);
                 int64_t streamNumber = 100;
                 streamNumber += wifi.AssignStreams(apDevice, streamNumber);
                 streamNumber += wifi.AssignStreams(staDevices, streamNumber);
@@ -461,6 +469,8 @@
                 InternetStackHelper stack;
                 stack.Install(wifiApNode);
                 stack.Install(wifiStaNodes);
+                streamNumber += stack.AssignStreams(wifiApNode, streamNumber);
+                streamNumber += stack.AssignStreams(wifiStaNodes, streamNumber);
 
                 Ipv4AddressHelper address;
                 address.SetBase("192.168.1.0", "255.255.255.0");
@@ -482,24 +492,31 @@
                     clientNodes.Add(downlink ? wifiApNode.Get(0) : wifiStaNodes.Get(i));
                 }
 
+                const auto maxLoad =
+                    nLinks * EhtPhy::GetDataRate(mcs, channelWidth, gi, 1) / nStations;
                 if (udp)
                 {
                     // UDP flow
                     uint16_t port = 9;
                     UdpServerHelper server(port);
                     serverApp = server.Install(serverNodes.get());
+                    streamNumber += server.AssignStreams(serverNodes.get(), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
+                    const auto packetInterval = payloadSize * 8.0 / maxLoad;
 
                     for (std::size_t i = 0; i < nStations; i++)
                     {
                         UdpClientHelper client(serverInterfaces.GetAddress(i), port);
                         client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-                        client.SetAttribute("Interval", TimeValue(Time("0.00001"))); // packets/s
+                        client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
                         client.SetAttribute("PacketSize", UintegerValue(payloadSize));
                         ApplicationContainer clientApp = client.Install(clientNodes.Get(i));
+                        streamNumber += client.AssignStreams(clientNodes.Get(i), streamNumber);
+
                         clientApp.Start(Seconds(1.0));
-                        clientApp.Stop(Seconds(simulationTime + 1));
+                        clientApp.Stop(simulationTime + Seconds(1.0));
                     }
                 }
                 else
@@ -509,8 +526,10 @@
                     Address localAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
                     PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
                     serverApp = packetSinkHelper.Install(serverNodes.get());
+                    streamNumber += packetSinkHelper.AssignStreams(serverNodes.get(), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
 
                     for (std::size_t i = 0; i < nStations; i++)
                     {
@@ -520,13 +539,15 @@
                         onoff.SetAttribute("OffTime",
                                            StringValue("ns3::ConstantRandomVariable[Constant=0]"));
                         onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-                        onoff.SetAttribute("DataRate", DataRateValue(1000000000)); // bit/s
+                        onoff.SetAttribute("DataRate", DataRateValue(maxLoad));
                         AddressValue remoteAddress(
                             InetSocketAddress(serverInterfaces.GetAddress(i), port));
                         onoff.SetAttribute("Remote", remoteAddress);
                         ApplicationContainer clientApp = onoff.Install(clientNodes.Get(i));
+                        streamNumber += onoff.AssignStreams(clientNodes.Get(i), streamNumber);
+
                         clientApp.Start(Seconds(1.0));
-                        clientApp.Stop(Seconds(simulationTime + 1));
+                        clientApp.Stop(simulationTime + Seconds(1.0));
                     }
                 }
 
@@ -542,20 +563,20 @@
                                         serverApp,
                                         payloadSize,
                                         tputInterval,
-                                        simulationTime + 1);
+                                        simulationTime + Seconds(1.0));
                 }
 
-                Simulator::Stop(Seconds(simulationTime + 1));
+                Simulator::Stop(simulationTime + Seconds(1.0));
                 Simulator::Run();
 
                 // When multiple stations are used, there are chances that association requests
                 // collide and hence the throughput may be lower than expected. Therefore, we relax
                 // the check that the throughput cannot decrease by introducing a scaling factor (or
                 // tolerance)
-                double tolerance = 0.10;
+                auto tolerance = 0.10;
                 cumulRxBytes = GetRxBytes(udp, serverApp, payloadSize);
-                uint64_t rxBytes = std::accumulate(cumulRxBytes.cbegin(), cumulRxBytes.cend(), 0);
-                double throughput = (rxBytes * 8) / (simulationTime * 1000000.0); // Mbit/s
+                auto rxBytes = std::accumulate(cumulRxBytes.cbegin(), cumulRxBytes.cend(), 0.0);
+                auto throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds(); // Mbit/s
 
                 Simulator::Destroy();
 
@@ -563,7 +584,7 @@
                           << throughput << " Mbit/s" << std::endl;
 
                 // test first element
-                if (mcs == 0 && channelWidth == 20 && gi == 3200)
+                if (mcs == minMcs && channelWidth == 20 && gi == 3200)
                 {
                     if (throughput * (1 + tolerance) < minExpectedThroughput)
                     {
@@ -572,7 +593,7 @@
                     }
                 }
                 // test last element
-                if (mcs == 11 && channelWidth == 160 && gi == 800)
+                if (mcs == maxMcs && channelWidth == maxChannelWidth && gi == 800)
                 {
                     if (maxExpectedThroughput > 0 &&
                         throughput > maxExpectedThroughput * (1 + tolerance))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-he-network.cc ns-3.42/examples/wireless/wifi-he-network.cc
--- ns-3.41/examples/wireless/wifi-he-network.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-he-network.cc	2024-05-29 15:29:46.912073100 -0700
@@ -32,7 +32,6 @@
 #include "ns3/on-off-helper.h"
 #include "ns3/packet-sink-helper.h"
 #include "ns3/packet-sink.h"
-#include "ns3/rng-seed-manager.h"
 #include "ns3/spectrum-wifi-helper.h"
 #include "ns3/ssid.h"
 #include "ns3/string.h"
@@ -74,9 +73,9 @@
     bool downlink{true};
     bool useRts{false};
     bool useExtendedBlockAck{false};
-    double simulationTime{10}; // seconds
-    double distance{1.0};      // meters
-    double frequency{5};       // whether 2.4, 5 or 6 GHz
+    Time simulationTime{"10s"};
+    double distance{1.0}; // meters
+    double frequency{5};  // whether 2.4, 5 or 6 GHz
     std::size_t nStations{1};
     std::string dlAckSeqType{"NO-OFDMA"};
     bool enableUlOfdma{false};
@@ -96,7 +95,7 @@
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("udp", "UDP if set to 1, TCP otherwise", udp);
     cmd.AddValue("downlink",
                  "Generate downlink flows if set to 1, uplink flows otherwise",
@@ -189,9 +188,10 @@
         uint8_t index = 0;
         double previous = 0;
         uint8_t maxChannelWidth = frequency == 2.4 ? 40 : 160;
+        int minGi = enableUlOfdma ? 1600 : 800;
         for (int channelWidth = 20; channelWidth <= maxChannelWidth;) // MHz
         {
-            for (int gi = 3200; gi >= 800;) // Nanoseconds
+            for (int gi = 3200; gi >= minGi;) // Nanoseconds
             {
                 if (!udp)
                 {
@@ -242,8 +242,7 @@
                 }
                 else
                 {
-                    std::cout << "Wrong frequency value!" << std::endl;
-                    return 0;
+                    NS_FATAL_ERROR("Wrong frequency value!");
                 }
 
                 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
@@ -323,8 +322,6 @@
                     apDevice = wifi.Install(phy, mac, wifiApNode);
                 }
 
-                RngSeedManager::SetSeed(1);
-                RngSeedManager::SetRun(1);
                 int64_t streamNumber = 150;
                 streamNumber += wifi.AssignStreams(apDevice, streamNumber);
                 streamNumber += wifi.AssignStreams(staDevices, streamNumber);
@@ -346,6 +343,8 @@
                 InternetStackHelper stack;
                 stack.Install(wifiApNode);
                 stack.Install(wifiStaNodes);
+                streamNumber += stack.AssignStreams(wifiApNode, streamNumber);
+                streamNumber += stack.AssignStreams(wifiStaNodes, streamNumber);
 
                 Ipv4AddressHelper address;
                 address.SetBase("192.168.1.0", "255.255.255.0");
@@ -367,24 +366,30 @@
                     clientNodes.Add(downlink ? wifiApNode.Get(0) : wifiStaNodes.Get(i));
                 }
 
+                const auto maxLoad = HePhy::GetDataRate(mcs, channelWidth, gi, 1) / nStations;
                 if (udp)
                 {
                     // UDP flow
                     uint16_t port = 9;
                     UdpServerHelper server(port);
                     serverApp = server.Install(serverNodes.get());
+                    streamNumber += server.AssignStreams(serverNodes.get(), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
+                    const auto packetInterval = payloadSize * 8.0 / maxLoad;
 
                     for (std::size_t i = 0; i < nStations; i++)
                     {
                         UdpClientHelper client(serverInterfaces.GetAddress(i), port);
                         client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-                        client.SetAttribute("Interval", TimeValue(Time("0.00001"))); // packets/s
+                        client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
                         client.SetAttribute("PacketSize", UintegerValue(payloadSize));
                         ApplicationContainer clientApp = client.Install(clientNodes.Get(i));
+                        streamNumber += client.AssignStreams(clientNodes.Get(i), streamNumber);
+
                         clientApp.Start(Seconds(1.0));
-                        clientApp.Stop(Seconds(simulationTime + 1));
+                        clientApp.Stop(simulationTime + Seconds(1.0));
                     }
                 }
                 else
@@ -394,8 +399,10 @@
                     Address localAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
                     PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
                     serverApp = packetSinkHelper.Install(serverNodes.get());
+                    streamNumber += packetSinkHelper.AssignStreams(serverNodes.get(), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
 
                     for (std::size_t i = 0; i < nStations; i++)
                     {
@@ -405,27 +412,29 @@
                         onoff.SetAttribute("OffTime",
                                            StringValue("ns3::ConstantRandomVariable[Constant=0]"));
                         onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-                        onoff.SetAttribute("DataRate", DataRateValue(1000000000)); // bit/s
+                        onoff.SetAttribute("DataRate", DataRateValue(maxLoad));
                         AddressValue remoteAddress(
                             InetSocketAddress(serverInterfaces.GetAddress(i), port));
                         onoff.SetAttribute("Remote", remoteAddress);
                         ApplicationContainer clientApp = onoff.Install(clientNodes.Get(i));
+                        streamNumber += onoff.AssignStreams(clientNodes.Get(i), streamNumber);
+
                         clientApp.Start(Seconds(1.0));
-                        clientApp.Stop(Seconds(simulationTime + 1));
+                        clientApp.Stop(simulationTime + Seconds(1.0));
                     }
                 }
 
                 Simulator::Schedule(Seconds(0), &Ipv4GlobalRoutingHelper::PopulateRoutingTables);
 
-                Simulator::Stop(Seconds(simulationTime + 1));
+                Simulator::Stop(simulationTime + Seconds(1.0));
                 Simulator::Run();
 
                 // When multiple stations are used, there are chances that association requests
                 // collide and hence the throughput may be lower than expected. Therefore, we relax
                 // the check that the throughput cannot decrease by introducing a scaling factor (or
                 // tolerance)
-                double tolerance = 0.10;
-                uint64_t rxBytes = 0;
+                auto tolerance = 0.10;
+                auto rxBytes = 0.0;
                 if (udp)
                 {
                     for (uint32_t i = 0; i < serverApp.GetN(); i++)
@@ -441,7 +450,7 @@
                         rxBytes += DynamicCast<PacketSink>(serverApp.Get(i))->GetTotalRx();
                     }
                 }
-                double throughput = (rxBytes * 8) / (simulationTime * 1000000.0); // Mbit/s
+                auto throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds(); // Mbit/s
 
                 Simulator::Destroy();
 
@@ -449,7 +458,7 @@
                           << throughput << " Mbit/s" << std::endl;
 
                 // test first element
-                if (mcs == 0 && channelWidth == 20 && gi == 3200)
+                if (mcs == minMcs && channelWidth == 20 && gi == 3200)
                 {
                     if (throughput * (1 + tolerance) < minExpectedThroughput)
                     {
@@ -458,7 +467,7 @@
                     }
                 }
                 // test last element
-                if (mcs == 11 && channelWidth == 160 && gi == 800)
+                if (mcs == maxMcs && channelWidth == maxChannelWidth && gi == 800)
                 {
                     if (maxExpectedThroughput > 0 &&
                         throughput > maxExpectedThroughput * (1 + tolerance))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-ht-network.cc ns-3.42/examples/wireless/wifi-ht-network.cc
--- ns-3.41/examples/wireless/wifi-ht-network.cc	2024-02-09 14:44:07.841789700 -0800
+++ ns-3.42/examples/wireless/wifi-ht-network.cc	2024-05-29 15:29:46.912073100 -0700
@@ -64,14 +64,14 @@
 int
 main(int argc, char* argv[])
 {
-    bool udp = true;
-    bool useRts = false;
-    double simulationTime = 10; // seconds
-    double distance = 1.0;      // meters
-    double frequency = 5.0;     // whether 2.4 or 5.0 GHz
-    int mcs = -1;               // -1 indicates an unset value
-    double minExpectedThroughput = 0;
-    double maxExpectedThroughput = 0;
+    bool udp{true};
+    bool useRts{false};
+    Time simulationTime{"10s"};
+    double distance{1.0}; // meters
+    double frequency{5};  // whether 2.4 or 5 GHz
+    int mcs{-1};          // -1 indicates an unset value
+    double minExpectedThroughput{0.0};
+    double maxExpectedThroughput{0.0};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("frequency",
@@ -80,7 +80,7 @@
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("udp", "UDP if set to 1, TCP otherwise", udp);
     cmd.AddValue("useRts", "Enable/disable RTS/CTS", useRts);
     cmd.AddValue("mcs", "if set, limit testing to a specific MCS (0-7)", mcs);
@@ -159,8 +159,7 @@
                 }
                 else
                 {
-                    std::cout << "Wrong frequency value!" << std::endl;
-                    return 0;
+                    NS_FATAL_ERROR("Wrong frequency value!");
                 }
 
                 auto nonHtRefRateMbps = HtPhy::GetNonHtReferenceRate(mcs) / 1e6;
@@ -197,6 +196,10 @@
                 NetDeviceContainer apDevice;
                 apDevice = wifi.Install(phy, mac, wifiApNode);
 
+                int64_t streamNumber = 150;
+                streamNumber += wifi.AssignStreams(apDevice, streamNumber);
+                streamNumber += wifi.AssignStreams(staDevice, streamNumber);
+
                 // mobility.
                 MobilityHelper mobility;
                 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
@@ -214,6 +217,8 @@
                 InternetStackHelper stack;
                 stack.Install(wifiApNode);
                 stack.Install(wifiStaNode);
+                streamNumber += stack.AssignStreams(wifiApNode, streamNumber);
+                streamNumber += stack.AssignStreams(wifiStaNode, streamNumber);
 
                 Ipv4AddressHelper address;
                 address.SetBase("192.168.1.0", "255.255.255.0");
@@ -224,6 +229,7 @@
                 apNodeInterface = address.Assign(apDevice);
 
                 /* Setting applications */
+                const auto maxLoad = HtPhy::GetDataRate(mcs, channelWidth, sgi ? 400 : 800, 1);
                 ApplicationContainer serverApp;
                 if (udp)
                 {
@@ -231,16 +237,21 @@
                     uint16_t port = 9;
                     UdpServerHelper server(port);
                     serverApp = server.Install(wifiStaNode.Get(0));
+                    streamNumber += server.AssignStreams(wifiStaNode.Get(0), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
+                    const auto packetInterval = payloadSize * 8.0 / maxLoad;
 
                     UdpClientHelper client(staNodeInterface.GetAddress(0), port);
                     client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-                    client.SetAttribute("Interval", TimeValue(Time("0.00001"))); // packets/s
+                    client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
                     client.SetAttribute("PacketSize", UintegerValue(payloadSize));
                     ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
+                    streamNumber += client.AssignStreams(wifiApNode.Get(0), streamNumber);
+
                     clientApp.Start(Seconds(1.0));
-                    clientApp.Stop(Seconds(simulationTime + 1));
+                    clientApp.Stop(simulationTime + Seconds(1.0));
                 }
                 else
                 {
@@ -249,8 +260,11 @@
                     Address localAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
                     PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
                     serverApp = packetSinkHelper.Install(wifiStaNode.Get(0));
+                    streamNumber +=
+                        packetSinkHelper.AssignStreams(wifiStaNode.Get(0), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
 
                     OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny());
                     onoff.SetAttribute("OnTime",
@@ -258,21 +272,23 @@
                     onoff.SetAttribute("OffTime",
                                        StringValue("ns3::ConstantRandomVariable[Constant=0]"));
                     onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-                    onoff.SetAttribute("DataRate", DataRateValue(200000000)); // bit/s
+                    onoff.SetAttribute("DataRate", DataRateValue(maxLoad));
                     AddressValue remoteAddress(
                         InetSocketAddress(staNodeInterface.GetAddress(0), port));
                     onoff.SetAttribute("Remote", remoteAddress);
                     ApplicationContainer clientApp = onoff.Install(wifiApNode.Get(0));
+                    streamNumber += onoff.AssignStreams(wifiApNode.Get(0), streamNumber);
+
                     clientApp.Start(Seconds(1.0));
-                    clientApp.Stop(Seconds(simulationTime + 1));
+                    clientApp.Stop(simulationTime + Seconds(1.0));
                 }
 
                 Ipv4GlobalRoutingHelper::PopulateRoutingTables();
 
-                Simulator::Stop(Seconds(simulationTime + 1));
+                Simulator::Stop(simulationTime + Seconds(1.0));
                 Simulator::Run();
 
-                uint64_t rxBytes = 0;
+                auto rxBytes = 0.0;
                 if (udp)
                 {
                     rxBytes = payloadSize * DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
@@ -281,7 +297,7 @@
                 {
                     rxBytes = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
                 }
-                double throughput = (rxBytes * 8) / (simulationTime * 1000000.0); // Mbit/s
+                auto throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds(); // Mbit/s
 
                 Simulator::Destroy();
 
@@ -289,7 +305,7 @@
                           << sgi << "\t\t\t" << throughput << " Mbit/s" << std::endl;
 
                 // test first element
-                if (mcs == 0 && channelWidth == 20 && !sgi)
+                if (mcs == minMcs && channelWidth == 20 && !sgi)
                 {
                     if (throughput < minExpectedThroughput)
                     {
@@ -297,7 +313,7 @@
                     }
                 }
                 // test last element
-                if (mcs == 7 && channelWidth == 40 && sgi)
+                if (mcs == maxMcs && channelWidth == 40 && sgi)
                 {
                     if (maxExpectedThroughput > 0 && throughput > maxExpectedThroughput)
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-mixed-network.cc ns-3.42/examples/wireless/wifi-mixed-network.cc
--- ns-3.41/examples/wireless/wifi-mixed-network.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-mixed-network.cc	2024-05-29 15:29:46.912073100 -0700
@@ -81,7 +81,7 @@
     bool nHasTraffic;              //!< True if 802.11n stations generate traffic
     bool isUdp;                    //!< True to generate UDP traffic
     uint32_t payloadSize;          //!< Payload size in bytes
-    double simulationTime;         //!< Simulation time in seconds
+    Time simulationTime;           //!< Simulation time
 };
 
 class Experiment
@@ -130,7 +130,7 @@
     uint32_t nWifiB = params.nWifiB;
     uint32_t nWifiG = params.nWifiG;
     uint32_t nWifiN = params.nWifiN;
-    double simulationTime = params.simulationTime;
+    auto simulationTime = params.simulationTime;
     uint32_t payloadSize = params.payloadSize;
 
     NodeContainer wifiBStaNodes;
@@ -277,7 +277,7 @@
         UdpServerHelper server(port);
         ApplicationContainer serverApp = server.Install(wifiApNode);
         serverApp.Start(Seconds(0.0));
-        serverApp.Stop(Seconds(simulationTime + 1));
+        serverApp.Stop(simulationTime + Seconds(1.0));
 
         UdpClientHelper client(ApInterface.GetAddress(0), port);
         client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -298,13 +298,13 @@
             clientApps.Add(client.Install(wifiNStaNodes));
         }
         clientApps.Start(Seconds(1.0));
-        clientApps.Stop(Seconds(simulationTime + 1));
+        clientApps.Stop(simulationTime + Seconds(1.0));
 
-        Simulator::Stop(Seconds(simulationTime + 1));
+        Simulator::Stop(simulationTime + Seconds(1.0));
         Simulator::Run();
 
-        uint64_t totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
-        throughput = totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0);
+        double totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
+        throughput = totalPacketsThrough * payloadSize * 8 / simulationTime.GetMicroSeconds();
     }
     else
     {
@@ -314,7 +314,7 @@
 
         ApplicationContainer serverApp = packetSinkHelper.Install(wifiApNode.Get(0));
         serverApp.Start(Seconds(0.0));
-        serverApp.Stop(Seconds(simulationTime + 1));
+        serverApp.Stop(simulationTime + Seconds(1.0));
 
         OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny());
         onoff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
@@ -339,13 +339,13 @@
             clientApps.Add(onoff.Install(wifiNStaNodes));
         }
         clientApps.Start(Seconds(1.0));
-        clientApps.Stop(Seconds(simulationTime + 1));
+        clientApps.Stop(simulationTime + Seconds(1.0));
 
-        Simulator::Stop(Seconds(simulationTime + 1));
+        Simulator::Stop(simulationTime + Seconds(1.0));
         Simulator::Run();
 
-        uint64_t totalPacketsThrough = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
-        throughput += totalPacketsThrough * 8 / (simulationTime * 1000000.0);
+        double totalPacketsThrough = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
+        throughput += totalPacketsThrough * 8 / simulationTime.GetMicroSeconds();
     }
     Simulator::Destroy();
     return throughput;
@@ -368,14 +368,14 @@
     params.nWifiN = 0;
     params.nHasTraffic = false;
     params.isUdp = true;
-    params.payloadSize = 1472;  // bytes
-    params.simulationTime = 10; // seconds
+    params.payloadSize = 1472; // bytes
+    params.simulationTime = Seconds(10);
 
     bool verifyResults = false; // used for regression
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", params.payloadSize);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", params.simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", params.simulationTime);
     cmd.AddValue("isUdp", "UDP if set to 1, TCP otherwise", params.isUdp);
     cmd.AddValue("verifyResults",
                  "Enable/disable results verification at the end of the simulation",
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-multirate.cc ns-3.42/examples/wireless/wifi-multirate.cc
--- ns-3.41/examples/wireless/wifi-multirate.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-multirate.cc	2024-05-29 15:29:46.912073100 -0700
@@ -480,7 +480,7 @@
     // Equipping the source  node with OnOff Application used for sending
     OnOffHelper onoff("ns3::UdpSocketFactory",
                       Address(InetSocketAddress(Ipv4Address("10.0.0.1"), m_port)));
-    onoff.SetConstantRate(DataRate(60000000));
+    onoff.SetConstantRate(DataRate(54000000));
     onoff.SetAttribute("PacketSize", UintegerValue(m_packetSize));
     onoff.SetAttribute("Remote", AddressValue(InetSocketAddress(ipv4AddrServer, m_port)));
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-multi-tos.cc ns-3.42/examples/wireless/wifi-multi-tos.cc
--- ns-3.41/examples/wireless/wifi-multi-tos.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-multi-tos.cc	2024-05-29 15:29:46.912073100 -0700
@@ -47,20 +47,20 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t nWifi = 4;
-    double simulationTime = 10; // seconds
-    double distance = 1.0;      // meters
-    uint16_t mcs = 7;
-    uint8_t channelWidth = 20; // MHz
-    bool useShortGuardInterval = false;
-    bool useRts = false;
+    uint32_t nWifi{4};
+    Time simulationTime{"10s"};
+    double distance{1.0}; // meters
+    uint16_t mcs{7};
+    uint8_t channelWidth{20}; // MHz
+    bool useShortGuardInterval{false};
+    bool useRts{false};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("nWifi", "Number of stations", nWifi);
     cmd.AddValue("distance",
                  "Distance in meters between the stations and the access point",
                  distance);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("useRts", "Enable/disable RTS/CTS", useRts);
     cmd.AddValue("mcs", "MCS value (0 - 7)", mcs);
     cmd.AddValue("channelWidth", "Channel width in MHz", channelWidth);
@@ -151,7 +151,6 @@
             auto ipv4 = wifiApNode.Get(0)->GetObject<Ipv4>();
             const auto address = ipv4->GetAddress(1, 0).GetLocal();
             InetSocketAddress sinkSocket(address, portNumber++);
-            sinkSocket.SetTos(tosValue);
             OnOffHelper onOffHelper("ns3::UdpSocketFactory", sinkSocket);
             onOffHelper.SetAttribute("OnTime",
                                      StringValue("ns3::ConstantRandomVariable[Constant=1]"));
@@ -159,6 +158,7 @@
                                      StringValue("ns3::ConstantRandomVariable[Constant=0]"));
             onOffHelper.SetAttribute("DataRate", DataRateValue(50000000 / nWifi));
             onOffHelper.SetAttribute("PacketSize", UintegerValue(1472)); // bytes
+            onOffHelper.SetAttribute("Tos", UintegerValue(tosValue));
             sourceApplications.Add(onOffHelper.Install(wifiStaNodes.Get(index)));
             PacketSinkHelper packetSinkHelper("ns3::UdpSocketFactory", sinkSocket);
             sinkApplications.Add(packetSinkHelper.Install(wifiApNode.Get(0)));
@@ -166,21 +166,21 @@
     }
 
     sinkApplications.Start(Seconds(0.0));
-    sinkApplications.Stop(Seconds(simulationTime + 1));
+    sinkApplications.Stop(simulationTime + Seconds(1.0));
     sourceApplications.Start(Seconds(1.0));
-    sourceApplications.Stop(Seconds(simulationTime + 1));
+    sourceApplications.Stop(simulationTime + Seconds(1.0));
 
     Ipv4GlobalRoutingHelper::PopulateRoutingTables();
 
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
     double throughput = 0;
     for (uint32_t index = 0; index < sinkApplications.GetN(); ++index)
     {
-        uint64_t totalPacketsThrough =
+        double totalPacketsThrough =
             DynamicCast<PacketSink>(sinkApplications.Get(index))->GetTotalRx();
-        throughput += ((totalPacketsThrough * 8) / (simulationTime * 1000000.0)); // Mbit/s
+        throughput += ((totalPacketsThrough * 8) / simulationTime.GetMicroSeconds()); // Mbit/s
     }
 
     Simulator::Destroy();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-power-adaptation-distance.cc ns-3.42/examples/wireless/wifi-power-adaptation-distance.cc
--- ns-3.41/examples/wireless/wifi-power-adaptation-distance.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-power-adaptation-distance.cc	2024-05-29 15:29:46.912073100 -0700
@@ -171,7 +171,7 @@
      * \param stepsSize The step size.
      * \param stepsTime Time on each step.
      */
-    void AdvancePosition(Ptr<Node> node, int stepsSize, int stepsTime);
+    void AdvancePosition(Ptr<Node> node, int stepsSize, Time stepsTime);
     /**
      * \brief Get the Position of a node.
      *
@@ -325,12 +325,12 @@
 }
 
 void
-NodeStatistics::AdvancePosition(Ptr<Node> node, int stepsSize, int stepsTime)
+NodeStatistics::AdvancePosition(Ptr<Node> node, int stepsSize, Time stepsTime)
 {
     Vector pos = GetPosition(node);
-    double mbs = ((m_bytesTotal * 8.0) / (1000000 * stepsTime));
+    double mbs = ((m_bytesTotal * 8.0) / stepsTime.GetMicroSeconds());
     m_bytesTotal = 0;
-    double atp = m_totalEnergy / stepsTime;
+    double atp = m_totalEnergy / stepsTime.GetSeconds();
     m_totalEnergy = 0;
     m_totalTime = 0;
     m_output_power.Add(pos.x, atp);
@@ -339,7 +339,7 @@
     SetPosition(node, pos);
     NS_LOG_INFO("At time " << Simulator::Now().GetSeconds() << " sec; setting new position to "
                            << pos);
-    Simulator::Schedule(Seconds(stepsTime),
+    Simulator::Schedule(stepsTime,
                         &NodeStatistics::AdvancePosition,
                         this,
                         node,
@@ -392,20 +392,20 @@
 int
 main(int argc, char* argv[])
 {
-    double maxPower = 17;
-    double minPower = 0;
-    uint32_t powerLevels = 18;
-
-    uint32_t rtsThreshold = 2346;
-    std::string manager = "ns3::ParfWifiManager";
-    std::string outputFileName = "parf";
-    int ap1_x = 0;
-    int ap1_y = 0;
-    int sta1_x = 5;
-    int sta1_y = 0;
-    uint32_t steps = 200;
-    uint32_t stepsSize = 1;
-    uint32_t stepsTime = 1;
+    double maxPower{17};
+    double minPower{0};
+    uint32_t powerLevels{18};
+
+    uint32_t rtsThreshold{2346};
+    std::string manager{"ns3::ParfWifiManager"};
+    std::string outputFileName{"parf"};
+    int ap1_x{0};
+    int ap1_y{0};
+    int sta1_x{5};
+    int sta1_y{0};
+    uint32_t steps{200};
+    uint32_t stepsSize{1};
+    Time stepsTime{"1s"};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("manager", "PRC Manager", manager);
@@ -431,7 +431,7 @@
         std::cout << "Exiting without running simulation; steps value of 0" << std::endl;
     }
 
-    uint32_t simuTime = (steps + 1) * stepsTime;
+    Time simuTime = (steps + 1) * stepsTime;
 
     // Define the APs
     NodeContainer wifiApNodes;
@@ -498,7 +498,7 @@
     NodeStatistics statistics = NodeStatistics(wifiApDevices, wifiStaDevices);
 
     // Move the STA by stepsSize meters every stepsTime seconds
-    Simulator::Schedule(Seconds(0.5 + stepsTime),
+    Simulator::Schedule(Seconds(0.5) + stepsTime,
                         &NodeStatistics::AdvancePosition,
                         &statistics,
                         wifiStaNodes.Get(0),
@@ -522,11 +522,11 @@
     OnOffHelper onoff("ns3::UdpSocketFactory", InetSocketAddress(sinkAddress, port));
     onoff.SetConstantRate(DataRate("54Mb/s"), packetSize);
     onoff.SetAttribute("StartTime", TimeValue(Seconds(0.5)));
-    onoff.SetAttribute("StopTime", TimeValue(Seconds(simuTime)));
+    onoff.SetAttribute("StopTime", TimeValue(simuTime));
     ApplicationContainer apps_source = onoff.Install(wifiApNodes.Get(0));
 
     apps_sink.Start(Seconds(0.5));
-    apps_sink.Stop(Seconds(simuTime));
+    apps_sink.Stop(simuTime);
 
     //------------------------------------------------------------
     //-- Setup stats and data collection
@@ -555,7 +555,7 @@
                         manager + "/RateChange",
                     MakeCallback(RateCallback));
 
-    Simulator::Stop(Seconds(simuTime));
+    Simulator::Stop(simuTime);
     Simulator::Run();
 
     std::ofstream outfile("throughput-" + outputFileName + ".plt");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-power-adaptation-interference.cc ns-3.42/examples/wireless/wifi-power-adaptation-interference.cc
--- ns-3.41/examples/wireless/wifi-power-adaptation-interference.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-power-adaptation-interference.cc	2024-05-29 15:29:46.912073100 -0700
@@ -456,22 +456,22 @@
 {
     // LogComponentEnable("ConstantRateWifiManager", LOG_LEVEL_FUNCTION);
 
-    double maxPower = 17;
-    double minPower = 0;
-    uint32_t powerLevels = 18;
-
-    uint32_t rtsThreshold = 2346;
-    std::string manager = "ns3::ParfWifiManager";
-    std::string outputFileName = "parf";
-    int ap1_x = 0;
-    int ap1_y = 0;
-    int sta1_x = 10;
-    int sta1_y = 0;
-    int ap2_x = 200;
-    int ap2_y = 0;
-    int sta2_x = 180;
-    int sta2_y = 0;
-    uint32_t simuTime = 100;
+    double maxPower{17};
+    double minPower{0};
+    uint32_t powerLevels{18};
+
+    uint32_t rtsThreshold{2346};
+    std::string manager{"ns3::ParfWifiManager"};
+    std::string outputFileName{"parf"};
+    int ap1_x{0};
+    int ap1_y{0};
+    int sta1_x{10};
+    int sta1_y{0};
+    int ap2_x{200};
+    int ap2_y{0};
+    int sta2_x{180};
+    int sta2_y{0};
+    Time simuTime{"100s"};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("manager", "PRC Manager", manager);
@@ -603,7 +603,7 @@
     apps_source.Add(onoff1.Install(wifiApNodes.Get(1)));
 
     apps_sink.Start(Seconds(0.5));
-    apps_sink.Stop(Seconds(simuTime));
+    apps_sink.Stop(simuTime);
 
     //------------------------------------------------------------
     //-- Setup stats and data collection
@@ -662,7 +662,7 @@
     FlowMonitorHelper flowmon;
     Ptr<FlowMonitor> monitor = flowmon.InstallAll();
 
-    Simulator::Stop(Seconds(simuTime));
+    Simulator::Stop(simuTime);
     Simulator::Run();
 
     Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier>(flowmon.GetClassifier());
@@ -686,7 +686,7 @@
                                            << "\n");
             NS_LOG_INFO("  Mean jitter:   "
                         << i->second.jitterSum.GetSeconds() / (i->second.rxPackets - 1) << "\n");
-            NS_LOG_INFO("  Tx Opp: " << 1 - (statisticsAp0.GetBusyTime() / simuTime));
+            NS_LOG_INFO("  Tx Opp: " << 1 - (statisticsAp0.GetBusyTime() / simuTime.GetSeconds()));
         }
         if (t.sourceAddress == "10.1.1.4" && t.destinationAddress == "10.1.1.2")
         {
@@ -704,7 +704,7 @@
                                            << "\n");
             NS_LOG_INFO("  Mean jitter:   "
                         << i->second.jitterSum.GetSeconds() / (i->second.rxPackets - 1) << "\n");
-            NS_LOG_INFO("  Tx Opp: " << 1 - (statisticsAp1.GetBusyTime() / simuTime));
+            NS_LOG_INFO("  Tx Opp: " << 1 - (statisticsAp1.GetBusyTime() / simuTime.GetSeconds()));
         }
     }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-rate-adaptation-distance.cc ns-3.42/examples/wireless/wifi-rate-adaptation-distance.cc
--- ns-3.41/examples/wireless/wifi-rate-adaptation-distance.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-rate-adaptation-distance.cc	2024-05-29 15:29:46.912073100 -0700
@@ -24,7 +24,7 @@
  * highlighting the power adaptation.
  *
  * This simulation consist of 2 nodes, one AP and one STA.
- * The AP generates UDP traffic with a CBR of 54 Mbps to the STA.
+ * The AP generates UDP traffic with a CBR of 400 Mbps to the STA.
  * The AP can use any power and rate control mechanism and the STA uses
  * only Minstrel rate control.
  * The STA can be configured to move away from (or towards to) the AP.
@@ -185,21 +185,21 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t rtsThreshold = 65535;
-    std::string staManager = "ns3::MinstrelHtWifiManager";
-    std::string apManager = "ns3::MinstrelHtWifiManager";
-    std::string standard = "802.11n-5GHz";
-    std::string outputFileName = "minstrelHT";
-    uint32_t BeMaxAmpduSize = 65535;
-    bool shortGuardInterval = false;
-    uint32_t chWidth = 20;
-    int ap1_x = 0;
-    int ap1_y = 0;
-    int sta1_x = 5;
-    int sta1_y = 0;
-    int steps = 100;
-    int stepsSize = 1;
-    int stepsTime = 1;
+    uint32_t rtsThreshold{65535};
+    std::string staManager{"ns3::MinstrelHtWifiManager"};
+    std::string apManager{"ns3::MinstrelHtWifiManager"};
+    std::string standard{"802.11n-5GHz"};
+    std::string outputFileName{"minstrelHT"};
+    uint32_t BeMaxAmpduSize{65535};
+    bool shortGuardInterval{false};
+    uint32_t chWidth{20};
+    int ap1_x{0};
+    int ap1_y{0};
+    int sta1_x{5};
+    int sta1_y{0};
+    int steps{100};
+    int stepsSize{1};
+    int stepsTime{1};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("staManager", "Rate adaptation manager of the STA", staManager);
@@ -224,7 +224,7 @@
     int simuTime = steps * stepsTime;
 
     if (standard != "802.11a" && standard != "802.11b" && standard != "802.11g" &&
-        standard == "802.11n-2.4GHz" && standard != "802.11n-5GHz" && standard != "802.11ac")
+        standard != "802.11n-2.4GHz" && standard != "802.11n-5GHz" && standard != "802.11ac")
     {
         NS_FATAL_ERROR("Standard " << standard << " is not supported by this program");
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-simple-adhoc.cc ns-3.42/examples/wireless/wifi-simple-adhoc.cc
--- ns-3.41/examples/wireless/wifi-simple-adhoc.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-simple-adhoc.cc	2024-05-29 15:29:46.912073100 -0700
@@ -110,22 +110,20 @@
 main(int argc, char* argv[])
 {
     std::string phyMode("DsssRate1Mbps");
-    double rss = -80;           // -dBm
-    uint32_t packetSize = 1000; // bytes
-    uint32_t numPackets = 1;
-    double interval = 1.0; // seconds
-    bool verbose = false;
+    double rss{-80};           // -dBm
+    uint32_t packetSize{1000}; // bytes
+    uint32_t numPackets{1};
+    Time interPacketInterval{"1s"};
+    bool verbose{false};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("phyMode", "Wifi Phy mode", phyMode);
     cmd.AddValue("rss", "received signal strength", rss);
     cmd.AddValue("packetSize", "size of application packet sent", packetSize);
     cmd.AddValue("numPackets", "number of packets generated", numPackets);
-    cmd.AddValue("interval", "interval (seconds) between packets", interval);
+    cmd.AddValue("interval", "interval between packets", interPacketInterval);
     cmd.AddValue("verbose", "turn on all WifiNetDevice log components", verbose);
     cmd.Parse(argc, argv);
-    // Convert to time object
-    Time interPacketInterval = Seconds(interval);
 
     // Fix non-unicast data rate to be the same as that of unicast
     Config::SetDefault("ns3::WifiRemoteStationManager::NonUnicastMode", StringValue(phyMode));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-simple-adhoc-grid.cc ns-3.42/examples/wireless/wifi-simple-adhoc-grid.cc
--- ns-3.41/examples/wireless/wifi-simple-adhoc-grid.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-simple-adhoc-grid.cc	2024-05-29 15:29:46.912073100 -0700
@@ -149,31 +149,29 @@
 int
 main(int argc, char* argv[])
 {
-    std::string phyMode("DsssRate1Mbps");
-    double distance = 100;      // m
-    uint32_t packetSize = 1000; // bytes
-    uint32_t numPackets = 1;
-    uint32_t numNodes = 25; // by default, 5x5
-    uint32_t sinkNode = 0;
-    uint32_t sourceNode = 24;
-    double interval = 1.0; // seconds
-    bool verbose = false;
-    bool tracing = false;
+    std::string phyMode{"DsssRate1Mbps"};
+    double distance{100};      // m
+    uint32_t packetSize{1000}; // bytes
+    uint32_t numPackets{1};
+    uint32_t numNodes{25}; // by default, 5x5
+    uint32_t sinkNode{0};
+    uint32_t sourceNode{24};
+    Time interPacketInterval{"1s"};
+    bool verbose{false};
+    bool tracing{false};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("phyMode", "Wifi Phy mode", phyMode);
     cmd.AddValue("distance", "distance (m)", distance);
     cmd.AddValue("packetSize", "size of application packet sent", packetSize);
     cmd.AddValue("numPackets", "number of packets generated", numPackets);
-    cmd.AddValue("interval", "interval (seconds) between packets", interval);
+    cmd.AddValue("interval", "interval (seconds) between packets", interPacketInterval);
     cmd.AddValue("verbose", "turn on all WifiNetDevice log components", verbose);
     cmd.AddValue("tracing", "turn on ascii and pcap tracing", tracing);
     cmd.AddValue("numNodes", "number of nodes", numNodes);
     cmd.AddValue("sinkNode", "Receiver node number", sinkNode);
     cmd.AddValue("sourceNode", "Sender node number", sourceNode);
     cmd.Parse(argc, argv);
-    // Convert to time object
-    Time interPacketInterval = Seconds(interval);
 
     // Fix non-unicast data rate to be the same as that of unicast
     Config::SetDefault("ns3::WifiRemoteStationManager::NonUnicastMode", StringValue(phyMode));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-simple-ht-hidden-stations.cc ns-3.42/examples/wireless/wifi-simple-ht-hidden-stations.cc
--- ns-3.41/examples/wireless/wifi-simple-ht-hidden-stations.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-simple-ht-hidden-stations.cc	2024-05-29 15:29:46.912073100 -0700
@@ -57,22 +57,22 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t payloadSize = 1472; // bytes
-    double simulationTime = 10;  // seconds
-    uint32_t nMpdus = 1;
-    uint32_t maxAmpduSize = 0;
-    bool enableRts = false;
-    double minExpectedThroughput = 0;
-    double maxExpectedThroughput = 0;
+    uint32_t payloadSize{1472}; // bytes
+    Time simulationTime{"10s"};
+    uint32_t nMpdus{1};
+    uint32_t maxAmpduSize{0};
+    bool enableRts{false};
+    double minExpectedThroughput{0};
+    double maxExpectedThroughput{0};
 
     RngSeedManager::SetSeed(1);
-    RngSeedManager::SetRun(5);
+    RngSeedManager::SetRun(7);
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("nMpdus", "Number of aggregated MPDUs", nMpdus);
     cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
     cmd.AddValue("enableRts", "Enable RTS/CTS", enableRts);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("minExpectedThroughput",
                  "if set, simulation fails if the lowest throughput is below this value",
                  minExpectedThroughput);
@@ -138,6 +138,10 @@
     Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/BE_MaxAmpduSize",
                 UintegerValue(maxAmpduSize));
 
+    int64_t streamNumber = 20;
+    streamNumber += wifi.AssignStreams(apDevice, streamNumber);
+    streamNumber += wifi.AssignStreams(staDevices, streamNumber);
+
     // Setting mobility model
     MobilityHelper mobility;
     Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
@@ -159,6 +163,8 @@
     InternetStackHelper stack;
     stack.Install(wifiApNode);
     stack.Install(wifiStaNodes);
+    streamNumber += stack.AssignStreams(wifiApNode, streamNumber);
+    streamNumber += stack.AssignStreams(wifiStaNodes, streamNumber);
 
     Ipv4AddressHelper address;
     address.SetBase("192.168.1.0", "255.255.255.0");
@@ -172,7 +178,8 @@
     UdpServerHelper server(port);
     ApplicationContainer serverApp = server.Install(wifiApNode);
     serverApp.Start(Seconds(0.0));
-    serverApp.Stop(Seconds(simulationTime + 1));
+    serverApp.Stop(simulationTime + Seconds(1.0));
+    streamNumber += server.AssignStreams(wifiApNode, streamNumber);
 
     UdpClientHelper client(ApInterface.GetAddress(0), port);
     client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -182,7 +189,8 @@
     // Saturated UDP traffic from stations to AP
     ApplicationContainer clientApp1 = client.Install(wifiStaNodes);
     clientApp1.Start(Seconds(1.0));
-    clientApp1.Stop(Seconds(simulationTime + 1));
+    clientApp1.Stop(simulationTime + Seconds(1.0));
+    streamNumber += client.AssignStreams(wifiStaNodes, streamNumber);
 
     phy.EnablePcap("SimpleHtHiddenStations_Ap", apDevice.Get(0));
     phy.EnablePcap("SimpleHtHiddenStations_Sta1", staDevices.Get(0));
@@ -191,15 +199,15 @@
     AsciiTraceHelper ascii;
     phy.EnableAsciiAll(ascii.CreateFileStream("SimpleHtHiddenStations.tr"));
 
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
 
     Simulator::Run();
 
-    uint64_t totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
+    double totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
 
     Simulator::Destroy();
 
-    double throughput = totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0);
+    auto throughput = totalPacketsThrough * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Throughput: " << throughput << " Mbit/s" << '\n';
     if (throughput < minExpectedThroughput ||
         (maxExpectedThroughput > 0 && throughput > maxExpectedThroughput))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-simple-infra.cc ns-3.42/examples/wireless/wifi-simple-infra.cc
--- ns-3.41/examples/wireless/wifi-simple-infra.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-simple-infra.cc	2024-05-29 15:29:46.912073100 -0700
@@ -142,12 +142,12 @@
 int
 main(int argc, char* argv[])
 {
-    std::string phyMode("DsssRate1Mbps");
-    double rss = -80;           // -dBm
-    uint32_t packetSize = 1000; // bytes
-    uint32_t numPackets = 1;
-    Time interval = Seconds(1.0);
-    bool verbose = false;
+    std::string phyMode{"DsssRate1Mbps"};
+    double rss{-80};           // -dBm
+    uint32_t packetSize{1000}; // bytes
+    uint32_t numPackets{1};
+    Time interval{"1s"};
+    bool verbose{false};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("phyMode", "Wifi Phy mode", phyMode);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-simple-interference.cc ns-3.42/examples/wireless/wifi-simple-interference.cc
--- ns-3.41/examples/wireless/wifi-simple-interference.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-simple-interference.cc	2024-05-29 15:29:46.916073000 -0700
@@ -160,22 +160,22 @@
 int
 main(int argc, char* argv[])
 {
-    std::string phyMode("DsssRate1Mbps");
-    double Prss = -80;           // -dBm
-    double Irss = -95;           // -dBm
-    double delta = 0;            // microseconds
-    uint32_t PpacketSize = 1000; // bytes
-    uint32_t IpacketSize = 1000; // bytes
-    bool verbose = false;
+    std::string phyMode{"DsssRate1Mbps"};
+    double Prss{-80};           // -dBm
+    double Irss{-95};           // -dBm
+    double delta{0};            // microseconds
+    uint32_t PpacketSize{1000}; // bytes
+    uint32_t IpacketSize{1000}; // bytes
+    bool verbose{false};
 
     // these are not command line arguments for this version
-    uint32_t numPackets = 1;
-    double interval = 1.0;       // seconds
-    double startTime = 10.0;     // seconds
-    double distanceToRx = 100.0; // meters
+    uint32_t numPackets{1};
+    Time interPacketInterval{"1s"};
+    Time startTime{"10s"};
+    double distanceToRx{100.0}; // meters
 
-    double offset = 91; // This is a magic number used to set the
-                        // transmit power, based on other configuration
+    double offset{91}; // This is a magic number used to set the
+                       // transmit power, based on other configuration
     CommandLine cmd(__FILE__);
     cmd.AddValue("phyMode", "Wifi Phy mode", phyMode);
     cmd.AddValue("Prss", "Intended primary received signal strength (dBm)", Prss);
@@ -185,8 +185,6 @@
     cmd.AddValue("IpacketSize", "size of interfering packet sent", IpacketSize);
     cmd.AddValue("verbose", "turn on all WifiNetDevice log components", verbose);
     cmd.Parse(argc, argv);
-    // Convert to time object
-    Time interPacketInterval = Seconds(interval);
 
     // Fix non-unicast data rate to be the same as that of unicast
     Config::SetDefault("ns3::WifiRemoteStationManager::NonUnicastMode", StringValue(phyMode));
@@ -269,7 +267,7 @@
                                         << " dBm at time offset=" << delta << " ms");
 
     Simulator::ScheduleWithContext(source->GetNode()->GetId(),
-                                   Seconds(startTime),
+                                   startTime,
                                    &GenerateTraffic,
                                    source,
                                    PpacketSize,
@@ -277,7 +275,7 @@
                                    interPacketInterval);
 
     Simulator::ScheduleWithContext(interferer->GetNode()->GetId(),
-                                   Seconds(startTime + delta / 1000000.0),
+                                   startTime + Seconds(delta / 1000000.0),
                                    &GenerateTraffic,
                                    interferer,
                                    IpacketSize,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-sleep.cc ns-3.42/examples/wireless/wifi-sleep.cc
--- ns-3.41/examples/wireless/wifi-sleep.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-sleep.cc	2024-05-29 15:29:46.916073000 -0700
@@ -62,6 +62,7 @@
 #include "ns3/yans-wifi-helper.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("WifiSleep");
 
@@ -109,23 +110,23 @@
 int
 main(int argc, char* argv[])
 {
-    std::string dataRate = "1Mbps";
-    uint32_t packetSize = 1000; // bytes
-    double duration = 10.0;     // seconds
-    double initialEnergy = 7.5; // joule
-    double voltage = 3.0;       // volts
-    double txPowerStart = 0.0;  // dbm
-    double txPowerEnd = 15.0;   // dbm
-    uint32_t nTxPowerLevels = 16;
-    uint32_t txPowerLevel = 0;
-    double idleCurrent = 0.273; // Ampere
-    double txCurrent = 0.380;   // Ampere
-    bool verbose = false;
+    DataRate dataRate{"1Mb/s"};
+    uint32_t packetSize{1000}; // bytes
+    Time duration{"10s"};
+    double initialEnergy{7.5}; // joule
+    double voltage{3.0};       // volts
+    double txPowerStart{0.0};  // dbm
+    double txPowerEnd{15.0};   // dbm
+    uint32_t nTxPowerLevels{16};
+    uint32_t txPowerLevel{0};
+    double idleCurrent{0.273}; // Ampere
+    double txCurrent{0.380};   // Ampere
+    bool verbose{false};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("dataRate", "Data rate", dataRate);
     cmd.AddValue("packetSize", "size of application packet sent", packetSize);
-    cmd.AddValue("duration", "duration (seconds) of the experiment", duration);
+    cmd.AddValue("duration", "duration of the experiment", duration);
     cmd.AddValue("initialEnergy", "Initial Energy (Joule) of each node", initialEnergy);
     cmd.AddValue("voltage", "Supply voltage (Joule)", voltage);
     cmd.AddValue("txPowerStart", "Minimum available transmission level (dbm)", txPowerStart);
@@ -196,13 +197,13 @@
     apps = onOff.Install(c.Get(0));
 
     apps.Start(Seconds(0.01));
-    apps.Stop(Seconds(duration));
+    apps.Stop(duration);
 
     // Create a packet sink to receive these packets
     PacketSinkHelper sink(transportProto, InetSocketAddress(Ipv4Address::GetAny(), 9001));
     apps = sink.Install(c.Get(1));
     apps.Start(Seconds(0.01));
-    apps.Stop(Seconds(duration));
+    apps.Stop(duration);
 
     // Energy sources
     EnergySourceContainer eSources;
@@ -255,7 +256,7 @@
     Config::Connect("/NodeList/0/DeviceList/*/Phy/State/State", MakeCallback(&PhyStateTrace<0>));
     Config::Connect("/NodeList/1/DeviceList/*/Phy/State/State", MakeCallback(&PhyStateTrace<1>));
 
-    Simulator::Stop(Seconds(duration + 1));
+    Simulator::Stop(duration + Seconds(1.0));
 
     Simulator::Run();
     Simulator::Destroy();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-spatial-reuse.cc ns-3.42/examples/wireless/wifi-spatial-reuse.cc
--- ns-3.41/examples/wireless/wifi-spatial-reuse.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-spatial-reuse.cc	2024-05-29 15:29:46.916073000 -0700
@@ -79,7 +79,7 @@
 //  thus increasing the amount of generated traffic by setting the
 //  interval argument to a lower value is necessary to see the
 //  benefits of spatial reuse in this scenario. This can, for
-//  instance, be accomplished by setting --interval=0.0001.
+//  instance, be accomplished by setting --interval=100us.
 //
 //  Spatial reuse reset events are traced in two text files:
 //  - wifi-spatial-reuse-resets-bss-1.txt (for STA 1)
@@ -156,29 +156,29 @@
 int
 main(int argc, char* argv[])
 {
-    double duration = 10.0;      // seconds
-    double d1 = 30.0;            // meters
-    double d2 = 30.0;            // meters
-    double d3 = 150.0;           // meters
-    double powSta1 = 10.0;       // dBm
-    double powSta2 = 10.0;       // dBm
-    double powAp1 = 21.0;        // dBm
-    double powAp2 = 21.0;        // dBm
-    double ccaEdTrSta1 = -62;    // dBm
-    double ccaEdTrSta2 = -62;    // dBm
-    double ccaEdTrAp1 = -62;     // dBm
-    double ccaEdTrAp2 = -62;     // dBm
-    double minimumRssi = -82;    // dBm
-    int channelWidth = 20;       // MHz
-    uint32_t payloadSize = 1500; // bytes
-    uint32_t mcs = 0;            // MCS value
-    double interval = 0.001;     // seconds
-    bool enableObssPd = true;
-    double obssPdThreshold = -72.0; // dBm
+    Time duration{"10s"};
+    double d1{30.0};            // meters
+    double d2{30.0};            // meters
+    double d3{150.0};           // meters
+    double powSta1{10.0};       // dBm
+    double powSta2{10.0};       // dBm
+    double powAp1{21.0};        // dBm
+    double powAp2{21.0};        // dBm
+    double ccaEdTrSta1{-62};    // dBm
+    double ccaEdTrSta2{-62};    // dBm
+    double ccaEdTrAp1{-62};     // dBm
+    double ccaEdTrAp2{-62};     // dBm
+    double minimumRssi{-82};    // dBm
+    int channelWidth{20};       // MHz
+    uint32_t payloadSize{1500}; // bytes
+    uint32_t mcs{0};            // MCS value
+    Time interval{"1ms"};
+    bool enableObssPd{true};
+    double obssPdThreshold{-72.0}; // dBm
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("duration", "Duration of simulation (s)", duration);
-    cmd.AddValue("interval", "Inter packet interval (s)", interval);
+    cmd.AddValue("duration", "Duration of simulation", duration);
+    cmd.AddValue("interval", "Inter packet interval", interval);
     cmd.AddValue("enableObssPd", "Enable/disable OBSS_PD", enableObssPd);
     cmd.AddValue("d1", "Distance between STA1 and AP1 (m)", d1);
     cmd.AddValue("d2", "Distance between STA2 and AP2 (m)", d2);
@@ -330,7 +330,7 @@
         wifiStaNodes.Get(0)->AddApplication(client);
         client->SetAttribute("PacketSize", UintegerValue(payloadSize));
         client->SetAttribute("MaxPackets", UintegerValue(0));
-        client->SetAttribute("Interval", TimeValue(Seconds(interval)));
+        client->SetAttribute("Interval", TimeValue(interval));
         Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
         server->SetLocal(socketAddr);
         wifiApNodes.Get(0)->AddApplication(server);
@@ -347,7 +347,7 @@
         wifiStaNodes.Get(1)->AddApplication(client);
         client->SetAttribute("PacketSize", UintegerValue(payloadSize));
         client->SetAttribute("MaxPackets", UintegerValue(0));
-        client->SetAttribute("Interval", TimeValue(Seconds(interval)));
+        client->SetAttribute("Interval", TimeValue(interval));
         Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
         server->SetLocal(socketAddr);
         wifiApNodes.Get(1)->AddApplication(server);
@@ -368,14 +368,14 @@
     // Pass in the context string "2" to allow the trace to distinguish objects
     hePhyB->GetObssPdAlgorithm()->TraceConnect("Reset", "2", MakeCallback(&ResetTrace));
 
-    Simulator::Stop(Seconds(duration));
+    Simulator::Stop(duration);
     Simulator::Run();
 
     Simulator::Destroy();
 
     for (uint32_t i = 0; i < 2; i++)
     {
-        double throughput = static_cast<double>(bytesReceived[2 + i]) * 8 / 1000 / 1000 / duration;
+        const auto throughput = bytesReceived[2 + i] * 8.0 / duration.GetMicroSeconds();
         std::cout << "Throughput for BSS " << i + 1 << ": " << throughput << " Mbit/s" << std::endl;
     }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-spectrum-per-example.cc ns-3.42/examples/wireless/wifi-spectrum-per-example.cc
--- ns-3.41/examples/wireless/wifi-spectrum-per-example.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-spectrum-per-example.cc	2024-05-29 15:29:46.916073000 -0700
@@ -64,7 +64,7 @@
 // Users may vary the following command-line arguments in addition to the
 // attributes, global values, and default values typically available:
 //
-//    --simulationTime:  Simulation time in seconds [10]
+//    --simulationTime:  Simulation time [10s]
 //    --udp:             UDP if set to 1, TCP otherwise [true]
 //    --distance:        meters separation between nodes [50]
 //    --index:           restrict index to single value between 0 and 31 [256]
@@ -128,17 +128,17 @@
 int
 main(int argc, char* argv[])
 {
-    bool udp = true;
-    double distance = 50;
-    double simulationTime = 10; // seconds
-    uint16_t index = 256;
-    std::string wifiType = "ns3::SpectrumWifiPhy";
-    std::string errorModelType = "ns3::NistErrorRateModel";
-    bool enablePcap = false;
-    const uint32_t tcpPacketSize = 1448;
+    bool udp{true};
+    double distance{50};
+    Time simulationTime{"10s"};
+    uint16_t index{256};
+    std::string wifiType{"ns3::SpectrumWifiPhy"};
+    std::string errorModelType{"ns3::NistErrorRateModel"};
+    bool enablePcap{false};
+    const uint32_t tcpPacketSize{1448};
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("udp", "UDP if set to 1, TCP otherwise", udp);
     cmd.AddValue("distance", "meters separation between nodes", distance);
     cmd.AddValue("index", "restrict index to single value between 0 and 31", index);
@@ -413,30 +413,10 @@
             apDevice = wifi.Install(spectrumPhy, mac, wifiApNode);
         }
 
-        if (i <= 7)
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(false));
-        }
-        else if (i > 7 && i <= 15)
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(true));
-        }
-        else if (i > 15 && i <= 23)
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(false));
-        }
-        else
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(true));
-        }
+        bool shortGuardIntervalSupported = (i > 7 && i <= 15) || (i > 23);
+        Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
+                    "ShortGuardIntervalSupported",
+                    BooleanValue(shortGuardIntervalSupported));
 
         // mobility.
         MobilityHelper mobility;
@@ -473,15 +453,16 @@
             UdpServerHelper server(port);
             serverApp = server.Install(wifiStaNode.Get(0));
             serverApp.Start(Seconds(0.0));
-            serverApp.Stop(Seconds(simulationTime + 1));
+            serverApp.Stop(simulationTime + Seconds(1.0));
+            const auto packetInterval = payloadSize * 8.0 / (datarate * 1e6);
 
             UdpClientHelper client(staNodeInterface.GetAddress(0), port);
             client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-            client.SetAttribute("Interval", TimeValue(Time("0.0001"))); // packets/s
+            client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
             client.SetAttribute("PacketSize", UintegerValue(payloadSize));
             ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
             clientApp.Start(Seconds(1.0));
-            clientApp.Stop(Seconds(simulationTime + 1));
+            clientApp.Stop(simulationTime + Seconds(1.0));
         }
         else
         {
@@ -491,18 +472,18 @@
             PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
             serverApp = packetSinkHelper.Install(wifiStaNode.Get(0));
             serverApp.Start(Seconds(0.0));
-            serverApp.Stop(Seconds(simulationTime + 1));
+            serverApp.Stop(simulationTime + Seconds(1.0));
 
             OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny());
             onoff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
             onoff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
             onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-            onoff.SetAttribute("DataRate", DataRateValue(1000000000)); // bit/s
+            onoff.SetAttribute("DataRate", DataRateValue(datarate * 1e6));
             AddressValue remoteAddress(InetSocketAddress(staNodeInterface.GetAddress(0), port));
             onoff.SetAttribute("Remote", remoteAddress);
             ApplicationContainer clientApp = onoff.Install(wifiApNode.Get(0));
             clientApp.Start(Seconds(1.0));
-            clientApp.Stop(Seconds(simulationTime + 1));
+            clientApp.Stop(simulationTime + Seconds(1.0));
         }
 
         Config::ConnectWithoutContext("/NodeList/0/DeviceList/*/Phy/MonitorSnifferRx",
@@ -519,24 +500,24 @@
         g_noiseDbmAvg = 0;
         g_samples = 0;
 
-        Simulator::Stop(Seconds(simulationTime + 1));
+        Simulator::Stop(simulationTime + Seconds(1.0));
         Simulator::Run();
 
-        double throughput = 0;
-        uint64_t totalPacketsThrough = 0;
+        auto throughput = 0.0;
+        auto totalPacketsThrough = 0.0;
         if (udp)
         {
             // UDP
             totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
             throughput =
-                totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0); // Mbit/s
+                totalPacketsThrough * payloadSize * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
         }
         else
         {
             // TCP
-            uint64_t totalBytesRx = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
+            auto totalBytesRx = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
             totalPacketsThrough = totalBytesRx / tcpPacketSize;
-            throughput = totalBytesRx * 8 / (simulationTime * 1000000.0); // Mbit/s
+            throughput = totalBytesRx * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
         }
         std::cout << std::setw(5) << i << std::setw(6) << (i % 8) << std::setprecision(2)
                   << std::fixed << std::setw(10) << datarate << std::setw(12) << throughput
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-spectrum-per-interference.cc ns-3.42/examples/wireless/wifi-spectrum-per-interference.cc
--- ns-3.41/examples/wireless/wifi-spectrum-per-interference.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-spectrum-per-interference.cc	2024-05-29 15:29:46.916073000 -0700
@@ -69,7 +69,7 @@
 // Users may vary the following command-line arguments in addition to the
 // attributes, global values, and default values typically available:
 //
-//    --simulationTime:  Simulation time in seconds [10]
+//    --simulationTime:  Simulation time [10s]
 //    --udp:             UDP if set to 1, TCP otherwise [true]
 //    --distance:        meters separation between nodes [50]
 //    --index:           restrict index to single value between 0 and 31 [256]
@@ -179,18 +179,18 @@
 int
 main(int argc, char* argv[])
 {
-    bool udp = true;
-    double distance = 50;
-    double simulationTime = 10; // seconds
-    uint16_t index = 256;
-    std::string wifiType = "ns3::SpectrumWifiPhy";
-    std::string errorModelType = "ns3::NistErrorRateModel";
-    bool enablePcap = false;
-    const uint32_t tcpPacketSize = 1448;
-    double waveformPower = 0;
+    bool udp{true};
+    double distance{50};
+    Time simulationTime{"10s"};
+    uint16_t index{256};
+    std::string wifiType{"ns3::SpectrumWifiPhy"};
+    std::string errorModelType{"ns3::NistErrorRateModel"};
+    bool enablePcap{false};
+    const uint32_t tcpPacketSize{1448};
+    double waveformPower{0};
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("udp", "UDP if set to 1, TCP otherwise", udp);
     cmd.AddValue("distance", "meters separation between nodes", distance);
     cmd.AddValue("index", "restrict index to single value between 0 and 31", index);
@@ -468,30 +468,10 @@
             apDevice = wifi.Install(spectrumPhy, mac, wifiApNode);
         }
 
-        if (i <= 7)
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(false));
-        }
-        else if (i > 7 && i <= 15)
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(true));
-        }
-        else if (i > 15 && i <= 23)
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(false));
-        }
-        else
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(true));
-        }
+        bool shortGuardIntervalSupported = (i > 7 && i <= 15) || (i > 23);
+        Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
+                    "ShortGuardIntervalSupported",
+                    BooleanValue(shortGuardIntervalSupported));
 
         // mobility.
         MobilityHelper mobility;
@@ -530,15 +510,16 @@
             UdpServerHelper server(port);
             serverApp = server.Install(wifiStaNode.Get(0));
             serverApp.Start(Seconds(0.0));
-            serverApp.Stop(Seconds(simulationTime + 1));
+            serverApp.Stop(simulationTime + Seconds(1.0));
+            const auto packetInterval = payloadSize * 8.0 / (datarate * 1e6);
 
             UdpClientHelper client(staNodeInterface.GetAddress(0), port);
             client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-            client.SetAttribute("Interval", TimeValue(Time("0.0001"))); // packets/s
+            client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
             client.SetAttribute("PacketSize", UintegerValue(payloadSize));
             ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
             clientApp.Start(Seconds(1.0));
-            clientApp.Stop(Seconds(simulationTime + 1));
+            clientApp.Stop(simulationTime + Seconds(1.0));
         }
         else
         {
@@ -548,18 +529,18 @@
             PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
             serverApp = packetSinkHelper.Install(wifiStaNode.Get(0));
             serverApp.Start(Seconds(0.0));
-            serverApp.Stop(Seconds(simulationTime + 1));
+            serverApp.Stop(simulationTime + Seconds(1.0));
 
             OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny());
             onoff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
             onoff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
             onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-            onoff.SetAttribute("DataRate", DataRateValue(1000000000)); // bit/s
+            onoff.SetAttribute("DataRate", DataRateValue(datarate * 1e6));
             AddressValue remoteAddress(InetSocketAddress(staNodeInterface.GetAddress(0), port));
             onoff.SetAttribute("Remote", remoteAddress);
             ApplicationContainer clientApp = onoff.Install(wifiApNode.Get(0));
             clientApp.Start(Seconds(1.0));
-            clientApp.Stop(Seconds(simulationTime + 1));
+            clientApp.Stop(simulationTime + Seconds(1.0));
         }
 
         // Configure waveform generator
@@ -623,24 +604,24 @@
                 "Error:  Wi-Fi nodes must be tuned to 5190 MHz to match the waveform generator");
         }
 
-        Simulator::Stop(Seconds(simulationTime + 1));
+        Simulator::Stop(simulationTime + Seconds(1.0));
         Simulator::Run();
 
-        double throughput = 0;
-        uint64_t totalPacketsThrough = 0;
+        auto throughput = 0.0;
+        auto totalPacketsThrough = 0.0;
         if (udp)
         {
             // UDP
             totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
             throughput =
-                totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0); // Mbit/s
+                totalPacketsThrough * payloadSize * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
         }
         else
         {
             // TCP
-            uint64_t totalBytesRx = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
+            auto totalBytesRx = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
             totalPacketsThrough = totalBytesRx / tcpPacketSize;
-            throughput = totalBytesRx * 8 / (simulationTime * 1000000.0); // Mbit/s
+            throughput = totalBytesRx * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
         }
         std::cout << std::setw(5) << i << std::setw(6) << (i % 8) << std::setprecision(2)
                   << std::fixed << std::setw(10) << datarate << std::setw(12) << throughput
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-spectrum-saturation-example.cc ns-3.42/examples/wireless/wifi-spectrum-saturation-example.cc
--- ns-3.41/examples/wireless/wifi-spectrum-saturation-example.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-spectrum-saturation-example.cc	2024-05-29 15:29:46.916073000 -0700
@@ -60,7 +60,7 @@
 // Users may vary the following command-line arguments in addition to the
 // attributes, global values, and default values typically available:
 //
-//    --simulationTime:  Simulation time in seconds [10]
+//    --simulationTime:  Simulation time [10s]
 //    --distance:        meters separation between nodes [1]
 //    --index:           restrict index to single value between 0 and 31 [256]
 //    --wifiType:        select ns3::SpectrumWifiPhy or ns3::YansWifiPhy [ns3::SpectrumWifiPhy]
@@ -100,16 +100,16 @@
 int
 main(int argc, char* argv[])
 {
-    double distance = 1;
-    double simulationTime = 10; // seconds
-    uint16_t index = 256;
-    uint32_t channelWidth = 0;
-    std::string wifiType = "ns3::SpectrumWifiPhy";
-    std::string errorModelType = "ns3::NistErrorRateModel";
-    bool enablePcap = false;
+    double distance{1};
+    Time simulationTime{"10s"};
+    uint16_t index{256};
+    uint32_t channelWidth{0};
+    std::string wifiType{"ns3::SpectrumWifiPhy"};
+    std::string errorModelType{"ns3::NistErrorRateModel"};
+    bool enablePcap{false};
 
     CommandLine cmd(__FILE__);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("distance", "meters separation between nodes", distance);
     cmd.AddValue("index", "restrict index to single value between 0 and 63", index);
     cmd.AddValue("wifiType", "select ns3::SpectrumWifiPhy or ns3::YansWifiPhy", wifiType);
@@ -152,25 +152,7 @@
             phy.Set("TxPowerStart", DoubleValue(1));
             phy.Set("TxPowerEnd", DoubleValue(1));
 
-            if (i > 31 && i <= 39)
-            {
-                phy.Set("Antennas", UintegerValue(2));
-                phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
-                phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
-            }
-            else if (i > 39 && i <= 47)
-            {
-                phy.Set("Antennas", UintegerValue(2));
-                phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
-                phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
-            }
-            else if (i > 47 && i <= 55)
-            {
-                phy.Set("Antennas", UintegerValue(2));
-                phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
-                phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
-            }
-            else if (i > 55 && i <= 63)
+            if (i > 31 && i <= 63)
             {
                 phy.Set("Antennas", UintegerValue(2));
                 phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
@@ -193,25 +175,7 @@
             spectrumPhy.Set("TxPowerStart", DoubleValue(1));
             spectrumPhy.Set("TxPowerEnd", DoubleValue(1));
 
-            if (i > 31 && i <= 39)
-            {
-                spectrumPhy.Set("Antennas", UintegerValue(2));
-                spectrumPhy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
-                spectrumPhy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
-            }
-            else if (i > 39 && i <= 47)
-            {
-                spectrumPhy.Set("Antennas", UintegerValue(2));
-                spectrumPhy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
-                spectrumPhy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
-            }
-            else if (i > 47 && i <= 55)
-            {
-                spectrumPhy.Set("Antennas", UintegerValue(2));
-                spectrumPhy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
-                spectrumPhy.Set("MaxSupportedRxSpatialStreams", UintegerValue(2));
-            }
-            else if (i > 55 && i <= 63)
+            if (i > 31 && i <= 63)
             {
                 spectrumPhy.Set("Antennas", UintegerValue(2));
                 spectrumPhy.Set("MaxSupportedTxSpatialStreams", UintegerValue(2));
@@ -588,30 +552,11 @@
             apDevice = wifi.Install(spectrumPhy, mac, wifiApNode);
         }
 
-        if ((i <= 7) || (i > 31 && i <= 39))
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(false));
-        }
-        else if ((i > 7 && i <= 15) || (i > 39 && i <= 47))
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(true));
-        }
-        else if ((i > 15 && i <= 23) || (i > 47 && i <= 55))
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(false));
-        }
-        else
-        {
-            Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
-                        "ShortGuardIntervalSupported",
-                        BooleanValue(true));
-        }
+        bool shortGuardIntervalSupported =
+            (i > 7 && i <= 15) || (i > 23 && i <= 31) || (i > 39 && i <= 47) || (i > 55);
+        Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/"
+                    "ShortGuardIntervalSupported",
+                    BooleanValue(shortGuardIntervalSupported));
 
         // mobility.
         MobilityHelper mobility;
@@ -644,15 +589,16 @@
         UdpServerHelper server(port);
         ApplicationContainer serverApp = server.Install(wifiStaNode.Get(0));
         serverApp.Start(Seconds(0.0));
-        serverApp.Stop(Seconds(simulationTime + 1));
+        serverApp.Stop(simulationTime + Seconds(1.0));
+        const auto packetInterval = payloadSize * 8.0 / (datarate * 1e6);
 
         UdpClientHelper client(staNodeInterface.GetAddress(0), port);
         client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-        client.SetAttribute("Interval", TimeValue(Time("0.0001"))); // packets/s
+        client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
         client.SetAttribute("PacketSize", UintegerValue(payloadSize));
         ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
         clientApp.Start(Seconds(1.0));
-        clientApp.Stop(Seconds(simulationTime + 1));
+        clientApp.Stop(simulationTime + Seconds(1.0));
 
         if (enablePcap)
         {
@@ -662,13 +608,12 @@
             phy.EnablePcap(ss.str(), apDevice);
         }
 
-        Simulator::Stop(Seconds(simulationTime + 1));
+        Simulator::Stop(simulationTime + Seconds(1.0));
         Simulator::Run();
 
-        double throughput;
-        uint64_t totalPacketsThrough;
-        totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
-        throughput = totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0); // Mbit/s
+        double totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
+        auto throughput =
+            totalPacketsThrough * payloadSize * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
         std::cout << std::setw(5) << i << std::setw(6) << (i % 8) + 8 * (i / 32) << std::setw(8)
                   << channelWidth << std::setw(10) << datarate << std::setw(12) << throughput
                   << std::setw(8) << totalPacketsThrough << std::endl;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-tcp.cc ns-3.42/examples/wireless/wifi-tcp.cc
--- ns-3.41/examples/wireless/wifi-tcp.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-tcp.cc	2024-05-29 15:29:46.916073000 -0700
@@ -72,12 +72,12 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t payloadSize = 1472;           /* Transport layer payload size in bytes. */
-    std::string dataRate = "100Mbps";      /* Application layer datarate. */
-    std::string tcpVariant = "TcpNewReno"; /* TCP variant type. */
-    std::string phyRate = "HtMcs7";        /* Physical layer bitrate. */
-    double simulationTime = 10;            /* Simulation time in seconds. */
-    bool pcapTracing = false;              /* PCAP Tracing is enabled or not. */
+    uint32_t payloadSize{1472};           /* Transport layer payload size in bytes. */
+    DataRate dataRate{"100Mb/s"};         /* Application layer datarate. */
+    std::string tcpVariant{"TcpNewReno"}; /* TCP variant type. */
+    std::string phyRate{"HtMcs7"};        /* Physical layer bitrate. */
+    Time simulationTime{"10s"};           /* Simulation time. */
+    bool pcapTracing{false};              /* PCAP Tracing is enabled or not. */
 
     /* Command line argument parser setup. */
     CommandLine cmd(__FILE__);
@@ -194,10 +194,11 @@
     }
 
     /* Start Simulation */
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
-    double averageThroughput = ((sink->GetTotalRx() * 8) / (1e6 * simulationTime));
+    auto averageThroughput =
+        (static_cast<double>(sink->GetTotalRx() * 8) / simulationTime.GetMicroSeconds());
 
     Simulator::Destroy();
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-timing-attributes.cc ns-3.42/examples/wireless/wifi-timing-attributes.cc
--- ns-3.41/examples/wireless/wifi-timing-attributes.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-timing-attributes.cc	2024-05-29 15:29:46.916073000 -0700
@@ -57,16 +57,16 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t slot = 9;          // slot time in microseconds
-    uint32_t sifs = 10;         // SIFS duration in microseconds
-    uint32_t pifs = 19;         // PIFS duration in microseconds
-    double simulationTime = 10; // simulation time in seconds
+    uint32_t slot{9};           // slot time in microseconds
+    uint32_t sifs{10};          // SIFS duration in microseconds
+    uint32_t pifs{19};          // PIFS duration in microseconds
+    Time simulationTime{"10s"}; // Simulation time
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("slot", "Slot time in microseconds", slot);
     cmd.AddValue("sifs", "SIFS duration in microseconds", sifs);
     cmd.AddValue("pifs", "PIFS duration in microseconds", pifs);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.Parse(argc, argv);
 
     // Since default reference loss is defined for 5 GHz, it needs to be changed when operating
@@ -146,7 +146,7 @@
     UdpServerHelper server(port);
     ApplicationContainer serverApp = server.Install(wifiStaNode.Get(0));
     serverApp.Start(Seconds(0.0));
-    serverApp.Stop(Seconds(simulationTime + 1));
+    serverApp.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper client(staNodeInterface.GetAddress(0), port);
     client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -155,18 +155,18 @@
 
     ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
     clientApp.Start(Seconds(1.0));
-    clientApp.Stop(Seconds(simulationTime + 1));
+    clientApp.Stop(simulationTime + Seconds(1.0));
 
     // Populate routing table
     Ipv4GlobalRoutingHelper::PopulateRoutingTables();
 
     // Set simulation time and launch simulation
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
     // Get and print results
-    uint64_t totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
-    double throughput = totalPacketsThrough * 1472 * 8 / (simulationTime * 1000000.0); // Mbit/s
+    double totalPacketsThrough = DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
+    auto throughput = totalPacketsThrough * 1472 * 8 / simulationTime.GetMicroSeconds(); // Mbit/s
     std::cout << "Throughput: " << throughput << " Mbit/s" << std::endl;
 
     Simulator::Destroy();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-txop-aggregation.cc ns-3.42/examples/wireless/wifi-txop-aggregation.cc
--- ns-3.41/examples/wireless/wifi-txop-aggregation.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-txop-aggregation.cc	2024-05-29 15:29:46.916073000 -0700
@@ -59,7 +59,7 @@
 //
 // The user can select the distance between the stations and the APs, can enable/disable the RTS/CTS
 // mechanism and can modify the duration of a TXOP. Example: ./ns3 run "wifi-txop-aggregation
-// --distance=10 --enableRts=0 --simulationTime=20"
+// --distance=10 --enableRts=0 --simulationTime=20s"
 //
 // The output prints the throughput and the maximum TXOP duration measured for the 4 cases/networks
 // described above. When default aggregation parameters are enabled, the
@@ -108,19 +108,19 @@
 int
 main(int argc, char* argv[])
 {
-    uint32_t payloadSize = 1472; // bytes
-    double simulationTime = 10;  // seconds
-    double txopLimit = 3520;     // microseconds
-    double distance = 5;         // meters
-    bool enableRts = false;
-    bool enablePcap = false;
-    bool verifyResults = false; // used for regression
+    uint32_t payloadSize{1472}; // bytes
+    Time simulationTime{"10s"};
+    double txopLimit{3520}; // microseconds
+    double distance{5};     // meters
+    bool enableRts{false};
+    bool enablePcap{false};
+    bool verifyResults{false}; // used for regression
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("payloadSize", "Payload size in bytes", payloadSize);
     cmd.AddValue("enableRts", "Enable or disable RTS/CTS", enableRts);
     cmd.AddValue("txopLimit", "TXOP duration in microseconds", txopLimit);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
@@ -173,6 +173,8 @@
                 SsidValue(ssid),
                 "EnableBeaconJitter",
                 BooleanValue(false));
+    // Modify EDCA configuration (TXOP limit) for AC_BE
+    mac.SetEdca(AC_BE, "TxopLimits", StringValue(std::to_string(txopLimit) + "us"));
     apDeviceA = wifi.Install(phy, mac, wifiApNodes.Get(0));
 
     // Modify EDCA configuration (TXOP limit) for AC_BE
@@ -182,7 +184,6 @@
     Ptr<QosTxop> edca;
     wifi_dev->GetMac()->GetAttribute("BE_Txop", ptr);
     edca = ptr.Get<QosTxop>();
-    edca->SetTxopLimit(MicroSeconds(txopLimit));
 
     // Trace TXOP duration for BE on AP A
     TxopDurationTracer netA;
@@ -205,6 +206,8 @@
                 SsidValue(ssid),
                 "EnableBeaconJitter",
                 BooleanValue(false));
+    // Modify EDCA configuration (TXOP limit) for AC_BE
+    mac.SetEdca(AC_BE, "TxopLimits", StringValue(std::to_string(txopLimit) + "us"));
     apDeviceB = wifi.Install(phy, mac, wifiApNodes.Get(1));
 
     // Disable A-MPDU
@@ -212,10 +215,8 @@
     wifi_dev = DynamicCast<WifiNetDevice>(dev);
     wifi_dev->GetMac()->SetAttribute("BE_MaxAmpduSize", UintegerValue(0));
 
-    // Modify EDCA configuration (TXOP limit) for AC_BE
     wifi_dev->GetMac()->GetAttribute("BE_Txop", ptr);
     edca = ptr.Get<QosTxop>();
-    edca->SetTxopLimit(MicroSeconds(txopLimit));
 
     // Trace TXOP duration for BE on AP B
     TxopDurationTracer netB;
@@ -240,6 +241,8 @@
                 SsidValue(ssid),
                 "EnableBeaconJitter",
                 BooleanValue(false));
+    // Modify EDCA configuration (TXOP limit) for AC_BE
+    mac.SetEdca(AC_BE, "TxopLimits", StringValue(std::to_string(txopLimit) + "us"));
     apDeviceC = wifi.Install(phy, mac, wifiApNodes.Get(2));
 
     // Disable A-MPDU and enable A-MSDU with the highest maximum size allowed by the standard (7935
@@ -249,10 +252,8 @@
     wifi_dev->GetMac()->SetAttribute("BE_MaxAmpduSize", UintegerValue(0));
     wifi_dev->GetMac()->SetAttribute("BE_MaxAmsduSize", UintegerValue(7935));
 
-    // Modify EDCA configuration (TXOP limit) for AC_BE
     wifi_dev->GetMac()->GetAttribute("BE_Txop", ptr);
     edca = ptr.Get<QosTxop>();
-    edca->SetTxopLimit(MicroSeconds(txopLimit));
 
     // Trace TXOP duration for BE on AP C
     TxopDurationTracer netC;
@@ -277,6 +278,8 @@
                 SsidValue(ssid),
                 "EnableBeaconJitter",
                 BooleanValue(false));
+    // Modify EDCA configuration (TXOP limit) for AC_BE
+    mac.SetEdca(AC_BE, "TxopLimits", StringValue(std::to_string(txopLimit) + "us"));
     apDeviceD = wifi.Install(phy, mac, wifiApNodes.Get(3));
 
     // Enable A-MPDU with a smaller size than the default one and
@@ -286,10 +289,8 @@
     wifi_dev->GetMac()->SetAttribute("BE_MaxAmpduSize", UintegerValue(32768));
     wifi_dev->GetMac()->SetAttribute("BE_MaxAmsduSize", UintegerValue(3839));
 
-    // Modify EDCA configuration (TXOP limit) for AC_BE
     wifi_dev->GetMac()->GetAttribute("BE_Txop", ptr);
     edca = ptr.Get<QosTxop>();
-    edca->SetTxopLimit(MicroSeconds(txopLimit));
 
     // Trace TXOP duration for BE on AP D
     TxopDurationTracer netD;
@@ -350,7 +351,7 @@
     UdpServerHelper serverA(port);
     ApplicationContainer serverAppA = serverA.Install(wifiStaNodes.Get(0));
     serverAppA.Start(Seconds(0.0));
-    serverAppA.Stop(Seconds(simulationTime + 1));
+    serverAppA.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientA(StaInterfaceA.GetAddress(0), port);
     clientA.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -359,12 +360,12 @@
 
     ApplicationContainer clientAppA = clientA.Install(wifiApNodes.Get(0));
     clientAppA.Start(Seconds(1.0));
-    clientAppA.Stop(Seconds(simulationTime + 1));
+    clientAppA.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverB(port);
     ApplicationContainer serverAppB = serverB.Install(wifiStaNodes.Get(1));
     serverAppB.Start(Seconds(0.0));
-    serverAppB.Stop(Seconds(simulationTime + 1));
+    serverAppB.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientB(StaInterfaceB.GetAddress(0), port);
     clientB.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -373,12 +374,12 @@
 
     ApplicationContainer clientAppB = clientB.Install(wifiApNodes.Get(1));
     clientAppB.Start(Seconds(1.0));
-    clientAppB.Stop(Seconds(simulationTime + 1));
+    clientAppB.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverC(port);
     ApplicationContainer serverAppC = serverC.Install(wifiStaNodes.Get(2));
     serverAppC.Start(Seconds(0.0));
-    serverAppC.Stop(Seconds(simulationTime + 1));
+    serverAppC.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientC(StaInterfaceC.GetAddress(0), port);
     clientC.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -387,12 +388,12 @@
 
     ApplicationContainer clientAppC = clientC.Install(wifiApNodes.Get(2));
     clientAppC.Start(Seconds(1.0));
-    clientAppC.Stop(Seconds(simulationTime + 1));
+    clientAppC.Stop(simulationTime + Seconds(1.0));
 
     UdpServerHelper serverD(port);
     ApplicationContainer serverAppD = serverD.Install(wifiStaNodes.Get(3));
     serverAppD.Start(Seconds(0.0));
-    serverAppD.Stop(Seconds(simulationTime + 1));
+    serverAppD.Stop(simulationTime + Seconds(1.0));
 
     UdpClientHelper clientD(StaInterfaceD.GetAddress(0), port);
     clientD.SetAttribute("MaxPackets", UintegerValue(4294967295U));
@@ -401,7 +402,7 @@
 
     ApplicationContainer clientAppD = clientD.Install(wifiApNodes.Get(3));
     clientAppD.Start(Seconds(1.0));
-    clientAppD.Stop(Seconds(simulationTime + 1));
+    clientAppD.Stop(simulationTime + Seconds(1.0));
 
     if (enablePcap)
     {
@@ -415,18 +416,18 @@
         phy.EnablePcap("STA_D", staDeviceD.Get(0));
     }
 
-    Simulator::Stop(Seconds(simulationTime + 1));
+    Simulator::Stop(simulationTime + Seconds(1.0));
     Simulator::Run();
 
     // Show results
-    uint64_t totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
-    uint64_t totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
+    double totalPacketsThroughA = DynamicCast<UdpServer>(serverAppA.Get(0))->GetReceived();
+    double totalPacketsThroughB = DynamicCast<UdpServer>(serverAppB.Get(0))->GetReceived();
+    double totalPacketsThroughC = DynamicCast<UdpServer>(serverAppC.Get(0))->GetReceived();
+    double totalPacketsThroughD = DynamicCast<UdpServer>(serverAppD.Get(0))->GetReceived();
 
     Simulator::Destroy();
 
-    double throughput = totalPacketsThroughA * payloadSize * 8 / (simulationTime * 1000000.0);
+    auto throughput = totalPacketsThroughA * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Default configuration (A-MPDU aggregation enabled, 65kB): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 57.5 || throughput > 58.5))
@@ -447,7 +448,7 @@
         }
     }
 
-    throughput = totalPacketsThroughB * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughB * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "Aggregation disabled: " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 38 || throughput > 39))
@@ -467,7 +468,7 @@
         }
     }
 
-    throughput = totalPacketsThroughC * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughC * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "A-MPDU disabled and A-MSDU enabled (8kB): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 52 || throughput > 53))
@@ -487,7 +488,7 @@
         }
     }
 
-    throughput = totalPacketsThroughD * payloadSize * 8 / (simulationTime * 1000000.0);
+    throughput = totalPacketsThroughD * payloadSize * 8 / simulationTime.GetMicroSeconds();
     std::cout << "A-MPDU enabled (32kB) and A-MSDU enabled (4kB): " << '\n'
               << "  Throughput = " << throughput << " Mbit/s" << '\n';
     if (verifyResults && (throughput < 58 || throughput > 59))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/examples/wireless/wifi-vht-network.cc ns-3.42/examples/wireless/wifi-vht-network.cc
--- ns-3.41/examples/wireless/wifi-vht-network.cc	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/examples/wireless/wifi-vht-network.cc	2024-05-29 15:29:46.916073000 -0700
@@ -62,19 +62,19 @@
 int
 main(int argc, char* argv[])
 {
-    bool udp = true;
-    bool useRts = false;
-    double simulationTime = 10; // seconds
-    double distance = 1.0;      // meters
-    int mcs = -1;               // -1 indicates an unset value
-    double minExpectedThroughput = 0;
-    double maxExpectedThroughput = 0;
+    bool udp{true};
+    bool useRts{false};
+    Time simulationTime{"10s"};
+    double distance{1.0}; // meters
+    int mcs{-1};          // -1 indicates an unset value
+    double minExpectedThroughput{0.0};
+    double maxExpectedThroughput{0.0};
 
     CommandLine cmd(__FILE__);
     cmd.AddValue("distance",
                  "Distance in meters between the station and the access point",
                  distance);
-    cmd.AddValue("simulationTime", "Simulation time in seconds", simulationTime);
+    cmd.AddValue("simulationTime", "Simulation time", simulationTime);
     cmd.AddValue("udp", "UDP if set to 1, TCP otherwise", udp);
     cmd.AddValue("useRts", "Enable/disable RTS/CTS", useRts);
     cmd.AddValue("mcs", "if set, limit testing to a specific MCS (0-9)", mcs);
@@ -178,6 +178,10 @@
                 NetDeviceContainer apDevice;
                 apDevice = wifi.Install(phy, mac, wifiApNode);
 
+                int64_t streamNumber = 150;
+                streamNumber += wifi.AssignStreams(apDevice, streamNumber);
+                streamNumber += wifi.AssignStreams(staDevice, streamNumber);
+
                 // mobility.
                 MobilityHelper mobility;
                 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
@@ -195,6 +199,8 @@
                 InternetStackHelper stack;
                 stack.Install(wifiApNode);
                 stack.Install(wifiStaNode);
+                streamNumber += stack.AssignStreams(wifiApNode, streamNumber);
+                streamNumber += stack.AssignStreams(wifiStaNode, streamNumber);
 
                 Ipv4AddressHelper address;
                 address.SetBase("192.168.1.0", "255.255.255.0");
@@ -205,6 +211,7 @@
                 apNodeInterface = address.Assign(apDevice);
 
                 /* Setting applications */
+                const auto maxLoad = VhtPhy::GetDataRate(mcs, channelWidth, sgi ? 400 : 800, 1);
                 ApplicationContainer serverApp;
                 if (udp)
                 {
@@ -212,16 +219,21 @@
                     uint16_t port = 9;
                     UdpServerHelper server(port);
                     serverApp = server.Install(wifiStaNode.Get(0));
+                    streamNumber += server.AssignStreams(wifiStaNode.Get(0), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
+                    const auto packetInterval = payloadSize * 8.0 / maxLoad;
 
                     UdpClientHelper client(staNodeInterface.GetAddress(0), port);
                     client.SetAttribute("MaxPackets", UintegerValue(4294967295U));
-                    client.SetAttribute("Interval", TimeValue(Time("0.00002"))); // packets/s
+                    client.SetAttribute("Interval", TimeValue(Seconds(packetInterval)));
                     client.SetAttribute("PacketSize", UintegerValue(payloadSize));
                     ApplicationContainer clientApp = client.Install(wifiApNode.Get(0));
+                    streamNumber += client.AssignStreams(wifiApNode.Get(0), streamNumber);
+
                     clientApp.Start(Seconds(1.0));
-                    clientApp.Stop(Seconds(simulationTime + 1));
+                    clientApp.Stop(simulationTime + Seconds(1.0));
                 }
                 else
                 {
@@ -230,8 +242,11 @@
                     Address localAddress(InetSocketAddress(Ipv4Address::GetAny(), port));
                     PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress);
                     serverApp = packetSinkHelper.Install(wifiStaNode.Get(0));
+                    streamNumber +=
+                        packetSinkHelper.AssignStreams(wifiStaNode.Get(0), streamNumber);
+
                     serverApp.Start(Seconds(0.0));
-                    serverApp.Stop(Seconds(simulationTime + 1));
+                    serverApp.Stop(simulationTime + Seconds(1.0));
 
                     OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny());
                     onoff.SetAttribute("OnTime",
@@ -239,21 +254,23 @@
                     onoff.SetAttribute("OffTime",
                                        StringValue("ns3::ConstantRandomVariable[Constant=0]"));
                     onoff.SetAttribute("PacketSize", UintegerValue(payloadSize));
-                    onoff.SetAttribute("DataRate", DataRateValue(1000000000)); // bit/s
+                    onoff.SetAttribute("DataRate", DataRateValue(maxLoad));
                     AddressValue remoteAddress(
                         InetSocketAddress(staNodeInterface.GetAddress(0), port));
                     onoff.SetAttribute("Remote", remoteAddress);
                     ApplicationContainer clientApp = onoff.Install(wifiApNode.Get(0));
+                    streamNumber += onoff.AssignStreams(wifiApNode.Get(0), streamNumber);
+
                     clientApp.Start(Seconds(1.0));
-                    clientApp.Stop(Seconds(simulationTime + 1));
+                    clientApp.Stop(simulationTime + Seconds(1.0));
                 }
 
                 Ipv4GlobalRoutingHelper::PopulateRoutingTables();
 
-                Simulator::Stop(Seconds(simulationTime + 1));
+                Simulator::Stop(simulationTime + Seconds(1.0));
                 Simulator::Run();
 
-                uint64_t rxBytes = 0;
+                auto rxBytes = 0.0;
                 if (udp)
                 {
                     rxBytes = payloadSize * DynamicCast<UdpServer>(serverApp.Get(0))->GetReceived();
@@ -262,7 +279,7 @@
                 {
                     rxBytes = DynamicCast<PacketSink>(serverApp.Get(0))->GetTotalRx();
                 }
-                double throughput = (rxBytes * 8) / (simulationTime * 1000000.0); // Mbit/s
+                auto throughput = (rxBytes * 8) / simulationTime.GetMicroSeconds(); // Mbit/s
 
                 Simulator::Destroy();
 
@@ -270,7 +287,7 @@
                           << sgi << "\t\t\t" << throughput << " Mbit/s" << std::endl;
 
                 // test first element
-                if (mcs == 0 && channelWidth == 20 && !sgi)
+                if (mcs == minMcs && channelWidth == 20 && !sgi)
                 {
                     if (throughput < minExpectedThroughput)
                     {
@@ -279,7 +296,7 @@
                     }
                 }
                 // test last element
-                if (mcs == 9 && channelWidth == 160 && sgi)
+                if (mcs == maxMcs && channelWidth == 160 && sgi)
                 {
                     if (maxExpectedThroughput > 0 && throughput > maxExpectedThroughput)
                     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/ns3 ns-3.42/ns3
--- ns-3.41/ns3	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/ns3	2024-05-29 15:29:46.916073000 -0700
@@ -10,7 +10,7 @@
 import subprocess
 import sys
 
-ns3_path = os.path.dirname(os.path.abspath(__file__))
+ns3_path = os.path.dirname(os.path.realpath(os.path.abspath(__file__)))
 append_to_ns3_path = functools.partial(os.path.join, ns3_path)
 out_dir = os.sep.join([ns3_path, "build"])
 lock_file = os.sep.join([ns3_path, ".lock-ns3_%s_build" % sys.platform])
@@ -618,7 +618,7 @@
 
 
 def remove_dir(dir_to_remove, dry_run, directory_qualifier=""):
-    dir_to_remove = os.path.abspath(dir_to_remove)
+    dir_to_remove = os.path.realpath(os.path.abspath(dir_to_remove))
     if os.path.exists(dir_to_remove):
         if ".." in os.path.relpath(dir_to_remove, ns3_path) or os.path.abspath(
             dir_to_remove
@@ -645,6 +645,7 @@
 
 
 def remove_file(file_to_remove, dry_run):
+    file_to_remove = os.path.realpath(file_to_remove)
     if os.path.exists(file_to_remove):
         print_and_buffer("rm -R %s" % os.path.relpath(file_to_remove, ns3_path))
         if not dry_run:
@@ -1225,7 +1226,7 @@
         print("Target to build does not exist: %s" % program_path)
         exit(1)
 
-    if "scratch" in program_path:
+    if "scratch" in os.path.relpath(program_path, ns3_path):
         # Get the path to the program and replace slashes with underlines
         # to get unique targets for CMake, preventing collisions with modules examples
         return program_name.replace(out_dir, "").replace("/", "_")[1:]
@@ -1412,6 +1413,9 @@
             debugging_software.extend(
                 [check_program_installed("valgrind"), "--leak-check=full", "--show-leak-kinds=all"]
             )
+            suppressions_file = os.path.join(ns3_path, ".ns3.supp")
+            if os.path.exists(suppressions_file):
+                debugging_software.append(f"--suppressions={suppressions_file}")
 
         # running gdb?
         if args.gdb:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/pyproject.toml ns-3.42/pyproject.toml
--- ns-3.41/pyproject.toml	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/pyproject.toml	2024-05-29 15:29:46.916073000 -0700
@@ -5,7 +5,7 @@
     "setuptools>=45",
     "setuptools_scm[toml]>=6.0",
     "cmake-build-extension>=0.4",
-    "cppyy==2.4.2",
+    "cppyy==3.1.2",
 ]
 
 [tool.setuptools_scm]
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/RELEASE_NOTES.md ns-3.42/RELEASE_NOTES.md
--- ns-3.41/RELEASE_NOTES.md	2024-02-09 14:44:07.721789000 -0800
+++ ns-3.42/RELEASE_NOTES.md	2024-05-29 15:30:03.724115800 -0700
@@ -13,6 +13,67 @@
 and references prefixed by '!' refer to a
 [GitLab.com merge request](https://gitlab.com/nsnam/ns-3-dev/-/merge_requests) number.
 
+Release 3.42
+------------
+
+In this release, we have introduced pedantic compiler warnings to enhance C++ standard conformance and improve portability.  Also, model library code in the lr-wpan and energy modules has been moved into a nested C++ namespace.
+
+### Availability
+
+This release is available from:
+<https://www.nsnam.org/release/ns-allinone-3.42.tar.bz2>
+
+### Supported platforms
+
+This release is intended to work on systems with the following minimal
+requirements (Note: not all ns-3 features are available on all systems):
+
+- g++-9 or later, or LLVM/clang++-10 or later
+- Python 3.6 or later
+- CMake 3.13 or later
+- (macOS only) Xcode 11 or later
+- (Windows only) Msys2/MinGW64 toolchain or WSL2
+
+Python API requires [Cppyy](https://cppyy.readthedocs.io/en/latest/installation.html) and has only
+been tested on Linux. As of this release, the latest known version to work with ns-3 is cppyy==3.1.2.
+
+### New user-visible features
+
+- (antenna) !1517 - Added `CircularApertureAntennaModel`, which mimics the reflector antenna with circular aperture described in 3GPP TR 38.811 v15.4.0, Section 6.4.1
+- (core) !1517 - Added `TestVector` iterators and dot product operator for `Vector2D` and `Vector3D` types
+- (energy) !1948 - Adds C++ namespace 'energy'
+- (lr-wpan) !1915 - Use MAC and PHY standard attribute ids
+- (lr-wpan) !1924 - Adds MAC attribute identifiers
+- (lr-wpan) !1927 - Adds standard version comments to MLME-GET.request function
+- (lr-wpan) !1926 - Adds C++ namespace 'lrwpan' and prefix shortening
+- (mobility) !1986 - Adds simple constant-mobility-example
+- (mobility) !1517 - Added the `GeocentricConstantPositionMobilityModel` mobility model and coordinate conversion methods between geocentric and topocentric coordinate systems
+- (propagation, spectrum) !1517 - Added 3GPP 38.811 Non-Terrestrial Networks channel model
+- (network) !1828 - Added a common helper to create and install applications
+- (wifi) - The `WifiMacHelper` provides a `SetDcf` and a `SetEdca` methods to configure attributes of `Txop` and `QosTxop` objects, respectively
+- (wifi) - The `ApWifiMac` provides new attributes (`CwMinsForSta`, `CwMaxsForSta`, `AifsnsForSta` and `TxopLimitsForSta`) to define the EDCA access parameters to include in the EDCA Parameter Set advertised to associated stations
+- (wifi) - The `WifiMacHelper` provides a `SetChannelAccessManager` and a `SetFrameExchangeManager` methods to configure attributes of `ChannelAccessManager` and `FrameExchangeManager` objects, respectively
+- (wifi) - Simulation duration and data rate parameters of existing wifi examples changed to use Time and DataRate types
+- (wifi) 1901! - Added WifiPhyRxTraceHelper for Wi-Fi Phy tracing
+
+### Bugs fixed
+
+- (bindings) - Preventing module namespace collision by checking if namespace exists before injecting it.
+- (bindings, core) #1059 - Resolved potential initialization issues in TimerImpl and ensured compatibility with Cppyy3.
+- (bindings, core) - Introduced a helper class to manage static initialization of Time as a workaround for Cppyy3 static initialization problems.
+- (bindings, lte, wifi) - Relocated statically initialized variables from header files to source files for Cppyy3 compatibility.
+- (build) #1048 - Resolved an issue with static and monolithic builds incorrectly linking to non-ns-3 libraries.
+- (build) #1058 - Corrected the behavior of the ./ns3 clean command in symlinked directories.
+- (build) #1065 - Rolled back the -Os optimization setting as the default on MacOS to address lld compatibility issues.
+- (core) #1060 - Addressed a stack overflow problem in MakeEvent.
+- (tests) - Enhanced error handling in test.py to avoid attempts to open non-existent XML files following early test termination by sanitizers.
+- (tcp) #735 - BBR fails to discard invalid samples
+- (tcp) #966 - Tcp Cubic (and LinuxReno) cwnd should not grow during application-limited phase
+- (tcp) #1085 - Do not reset Cubic W_max upon timeout
+- (wifi) #1072 - Support configuration of custom EDCA parameters via Txop attributes before device installation
+- (wifi) - Fix operation in 6 GHz band (added support for FILS Discovery frames and HE 6GHz Band Capabilities information element, fixed HE Operation information element, fixed NSS selection, fixed HT and VHT not supported on 6GHz links).
+- (wifi, spectrum) - Fix negative power when channel is switched during the propagation delay period (after TX started but before the signal reached RX).
+
 Release 3.41
 ------------
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/setup.cfg ns-3.42/setup.cfg
--- ns-3.41/setup.cfg	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/setup.cfg	2024-05-29 15:29:46.916073000 -0700
@@ -40,5 +40,5 @@
 zip_safe = False
 python_requires = >=3.6
 install_requires =
-    cppyy==2.4.2
+    cppyy==3.1.2
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/CMakeLists.txt ns-3.42/src/antenna/CMakeLists.txt
--- ns-3.41/src/antenna/CMakeLists.txt	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/src/antenna/CMakeLists.txt	2024-05-29 15:29:46.916073000 -0700
@@ -1,6 +1,61 @@
+# Check for dependencies and add sources accordingly
+check_cxx_source_compiles(
+  "#include <cmath>
+    int main()
+    {
+      return std::cyl_bessel_j(1, 1);
+    }"
+  HAVE_STD_BESSEL_FUNC
+)
+
+set(circular_aperture_antenna_sources)
+set(circular_aperture_antenna_headers)
+set(circular_aperture_antenna_test_sources)
+
+if(${HAVE_STD_BESSEL_FUNC})
+  set(circular_aperture_antenna_sources
+      model/circular-aperture-antenna-model.cc
+  )
+  set(circular_aperture_antenna_headers
+      model/circular-aperture-antenna-model.h
+  )
+  set(circular_aperture_antenna_test_sources
+      test/test-circular-aperture-antenna.cc
+  )
+  message(STATUS "Standard library Bessel function has been found")
+else()
+  check_include_files(
+    "boost/math/special_functions/bessel.hpp"
+    HAVE_BOOST_BESSEL_FUNC
+    LANGUAGE
+    CXX
+  )
+  if(${HAVE_BOOST_BESSEL_FUNC})
+    set(circular_aperture_antenna_sources
+        model/circular-aperture-antenna-model.cc
+    )
+    set(circular_aperture_antenna_headers
+        model/circular-aperture-antenna-model.h
+    )
+    set(circular_aperture_antenna_test_sources
+        test/test-circular-aperture-antenna.cc
+    )
+    add_definitions(-DNEED_AND_HAVE_BOOST_BESSEL_FUNC)
+    message(STATUS "Boost Bessel function has been found.")
+  else()
+    message(
+      STATUS
+        "Boost Bessel function is required for CircularApertureAntennaModel"
+        " on platforms using Clang libc++ such as macOS."
+        " You may need to clean up the CMake cache after installing it to pass this check."
+    )
+  endif()
+endif()
+
 build_lib(
   LIBNAME antenna
   SOURCE_FILES
+    ${circular_aperture_antenna_sources}
     model/angles.cc
     model/antenna-model.cc
     model/cosine-antenna-model.cc
@@ -10,6 +65,7 @@
     model/three-gpp-antenna-model.cc
     model/uniform-planar-array.cc
   HEADER_FILES
+    ${circular_aperture_antenna_headers}
     model/angles.h
     model/antenna-model.h
     model/cosine-antenna-model.h
@@ -20,10 +76,11 @@
     model/uniform-planar-array.h
   LIBRARIES_TO_LINK ${libcore}
   TEST_SOURCES
+    ${circular_aperture_antenna_test_sources}
     test/test-angles.cc
+    test/test-cosine-antenna.cc
     test/test-degrees-radians.cc
     test/test-isotropic-antenna.cc
-    test/test-cosine-antenna.cc
     test/test-parabolic-antenna.cc
     test/test-uniform-planar-array.cc
 )
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/doc/Makefile ns-3.42/src/antenna/doc/Makefile
--- ns-3.41/src/antenna/doc/Makefile	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/src/antenna/doc/Makefile	2024-05-29 15:29:46.916073000 -0700
@@ -40,7 +40,7 @@
 	@if test x$($@_width) != x; then $(RESCALE) $($@_width) $@ ; fi
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/doc/source/antenna-design.rst ns-3.42/src/antenna/doc/source/antenna-design.rst
--- ns-3.41/src/antenna/doc/source/antenna-design.rst	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/doc/source/antenna-design.rst	2024-05-29 15:29:46.916073000 -0700
@@ -113,7 +113,9 @@
 ParabolicAntennaModel
 +++++++++++++++++++++
 
-This model is based on the parabolic approximation of the main lobe radiation pattern. It is often used in the context of cellular system to model the radiation pattern of a cell sector, see for instance [R4-092042a]_ and [Calcev]_. The antenna gain in dB is determined as:
+This model is based on the parabolic approximation of the main lobe radiation pattern. It is often
+used in the context of cellular system to model the radiation pattern of a cell sector, see for
+instance [R4-092042a]_ and [Calcev]_. The antenna gain in dB is determined as:
 
 .. math::
 
@@ -174,7 +176,7 @@
 and "AntennaVerticalSpacing".
 
 UniformPlannarArray supports the concept of antenna ports following the sub-array partition
-model for TXRU virtualization, as described in Section 5.2.2 of 3GPP TR 36.897 [36897]_.
+model for TXRU virtualization, as described in Section 5.2.2 of 3GPP TR 36.897 [3GPP_TR36897]_.
 The number of antenna ports in vertical and horizontal directions can be configured through
 the attributes "NumVerticalPorts" and "NumHorizontalPorts", respectively. For example,
 if "NumRows" and "NumColumns" are configured to 2 and 4, and the number of
@@ -192,6 +194,40 @@
 the second polarization have the polarization slant angle minus 90 degrees,
 as described in [38901]_ (i.e., :math:`{\zeta}`).
 
+CircularApertureAntennaModel
+++++++++++++++++++++++++++++
+
+The class CircularApertureAntennaModel implements the radiation pattern described in [38811]_.
+Specifically, the latter represents parabolic antennas, i.e., antennas which are typically used
+for achieving long range communications such as earth-to-satellite links.
+The default boresight orientation is parallel to the positive z-axis, and it can be tuned by
+using the AntennaInclination and AntennaAzimuth parameters.
+This implementation provides an exact characterization of the antenna field pattern, by leveraging
+the standard library Bessel functions implementation introduced with C++17.
+Accordingly, the antenna gain :math:`G` at an angle :math:`\theta` from the boresight main beam
+is evaluated as:
+
+.. math::
+   G \cdot 4\left | \frac{J_{1}\left ( k\cdot a\cdot sin\theta \right )}{k\cdot a\cdot sin\theta} \right
+   |^{2}\;\;\;\;\; for\; 0<\left | \theta \right |\leq 90^{\circ} \\
+   G \cdot 1\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\; for\; \theta=0
+
+where :math:`J_{1}()` is the Bessel function of the first kind and first order, and :math:`a` is
+the radius of the antenna's circular aperture.
+The parameter :math:`k` is equal to :math:`k=\frac{2\pi f}{x}`, where :math:`f` is the carrier
+frequency, and :math:`c` is the speed of light in vacuum.
+The parameters :math:`G` (in logarithmic scale), :math:`a` and :math:`f` can be configured by using
+the attributes "AntennaMaxGainDb", "AntennaCircularApertureRadius" and "OperatingFrequency", respectively.
+This type of antennas features a symmetric radiation pattern, meaning that a single angle, measured
+from the boresight direction, is sufficient to characterize the radiation strength along a given direction.
+
+.. _fig-circular-antenna-pattern:
+
+.. figure:: figures/circular-antenna-pattern.png
+   :align: center
+
+   Circular aperture antenna radiation pattern with :math:`G =` 38.5 dB and :math:`a =` 10 :math:`\frac{c}{f}.`
+
 
 .. [Balanis] C.A. Balanis, "Antenna Theory - Analysis and Design",  Wiley, 2nd Ed.
 
@@ -208,7 +244,9 @@
 
 .. [38901] 3GPP. 2018. TR 38.901, Study on channel model for frequencies from 0.5 to 100 GHz, V15.0.0. (2018-06).
 
+.. [38811] 3GPP. 2018. TR 38.811, Study on New Radio (NR) to support non-terrestrial networks, V15.4.0. (2020-09).
+
 .. [Mailloux] Robert J. Mailloux, "Phased Array Antenna Handbook", Artech House, 2nd Ed.
 
-.. [TR36897] 3GPP. 2015. TR 36.897. Study on elevation beamforming / Full-Dimension (FD)
+.. [3GPP_TR36897] 3GPP. 2015. TR 36.897. Study on elevation beamforming / Full-Dimension (FD)
    Multiple Input Multiple Output (MIMO) for LTE. V13.0.0. (2015-06)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/model/angles.cc ns-3.42/src/antenna/model/angles.cc
--- ns-3.41/src/antenna/model/angles.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/model/angles.cc	2024-05-29 15:29:46.916073000 -0700
@@ -210,8 +210,9 @@
     // azimuth and inclination angles for zero-length vectors are not defined
     if (v.x == 0.0 && v.y == 0.0 && v.z == 0.0)
     {
-        m_azimuth = NAN;
-        m_inclination = NAN;
+        // assume x and length equals to 1 mm to avoid nans
+        m_azimuth = std::atan2(v.y, 0.001);
+        m_inclination = std::acos(v.z / 0.001);
     }
 
     NormalizeAngles();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/model/circular-aperture-antenna-model.cc ns-3.42/src/antenna/model/circular-aperture-antenna-model.cc
--- ns-3.41/src/antenna/model/circular-aperture-antenna-model.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/antenna/model/circular-aperture-antenna-model.cc	2024-05-29 15:29:46.916073000 -0700
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2022 University of Padova, Dep. of Information Engineering, SIGNET lab.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mattia Sandri <mattia.sandri@unipd.it>
+ */
+
+#include "circular-aperture-antenna-model.h"
+
+// The host system uses Clang libc++, which does not support the Mathematical special functions
+// (P0226R1) and Boost's implementation of cyl_bessel_j has been found.
+#ifdef NEED_AND_HAVE_BOOST_BESSEL_FUNC
+#include <boost/math/special_functions/bessel.hpp>
+#endif
+
+#include "antenna-model.h"
+
+#include <ns3/double.h>
+#include <ns3/log.h>
+
+#include <math.h>
+
+/**
+ *  \file
+ *  \ingroup antenna
+ *  Class CircularApertureAntennaModel implementation.
+ */
+
+namespace
+{
+constexpr double C = 299792458.0; ///< speed of light in vacuum, in m/s
+} // namespace
+
+namespace ns3
+{
+NS_LOG_COMPONENT_DEFINE("CircularApertureAntennaModel");
+
+NS_OBJECT_ENSURE_REGISTERED(CircularApertureAntennaModel);
+
+TypeId
+CircularApertureAntennaModel::GetTypeId()
+{
+    static TypeId tid =
+        TypeId("ns3::CircularApertureAntennaModel")
+            .SetParent<AntennaModel>()
+            .SetGroupName("Antenna")
+            .AddConstructor<CircularApertureAntennaModel>()
+            .AddAttribute("AntennaCircularApertureRadius",
+                          "The radius of the aperture of the antenna, in meters",
+                          DoubleValue(0.5),
+                          MakeDoubleAccessor(&CircularApertureAntennaModel::SetApertureRadius),
+                          MakeDoubleChecker<double>(0.0))
+            .AddAttribute("OperatingFrequency",
+                          "The operating frequency in Hz of the antenna",
+                          DoubleValue(2e9),
+                          MakeDoubleAccessor(&CircularApertureAntennaModel::SetOperatingFrequency),
+                          MakeDoubleChecker<double>(0.0))
+            .AddAttribute("AntennaMinGainDb",
+                          "The minimum gain value in dB of the antenna",
+                          DoubleValue(-100.0),
+                          MakeDoubleAccessor(&CircularApertureAntennaModel::SetMinGain),
+                          MakeDoubleChecker<double>())
+            .AddAttribute("AntennaMaxGainDb",
+                          "The maximum gain value in dB of the antenna",
+                          DoubleValue(1),
+                          MakeDoubleAccessor(&CircularApertureAntennaModel::SetMaxGain),
+                          MakeDoubleChecker<double>(0.0));
+    return tid;
+}
+
+void
+CircularApertureAntennaModel::SetApertureRadius(double aMeter)
+{
+    NS_LOG_FUNCTION(this << aMeter);
+    NS_ASSERT_MSG(aMeter > 0, "Setting invalid aperture radius: " << aMeter);
+    m_apertureRadiusMeter = aMeter;
+}
+
+double
+CircularApertureAntennaModel::GetApertureRadius() const
+{
+    return m_apertureRadiusMeter;
+}
+
+void
+CircularApertureAntennaModel::SetOperatingFrequency(double freqHz)
+{
+    NS_LOG_FUNCTION(this << freqHz);
+    NS_ASSERT_MSG(freqHz > 0, "Setting invalid operating frequency: " << freqHz);
+    m_operatingFrequencyHz = freqHz;
+}
+
+double
+CircularApertureAntennaModel::GetOperatingFrequency() const
+{
+    return m_operatingFrequencyHz;
+}
+
+void
+CircularApertureAntennaModel::SetMaxGain(double gainDb)
+{
+    NS_LOG_FUNCTION(this << gainDb);
+    m_maxGain = gainDb;
+}
+
+double
+CircularApertureAntennaModel::GetMaxGain() const
+{
+    return m_maxGain;
+}
+
+void
+CircularApertureAntennaModel::SetMinGain(double gainDb)
+{
+    NS_LOG_FUNCTION(this << gainDb);
+    m_minGain = gainDb;
+}
+
+double
+CircularApertureAntennaModel::GetMinGain() const
+{
+    return m_minGain;
+}
+
+double
+CircularApertureAntennaModel::GetGainDb(Angles a)
+{
+    NS_LOG_FUNCTION(this << a);
+
+    // In 3GPP TR 38.811 v15.4.0, Section 6.4.1, the gain depends on a single angle only.
+    // We assume that this angle represents the angle between the vectors corresponding
+    // to the cartesian coordinates of the provided spherical coordinates, and the spherical
+    // coordinates (r = 1, azimuth = 0, elevation = PI/2)
+    double theta1 = a.GetInclination();
+    double theta2 = M_PI_2; // reference direction
+
+    // Convert to ISO range: the input azimuth angle phi is in [-pi,pi],
+    // while the ISO convention for spherical to cartesian coordinates
+    // assumes phi in [0,2*pi].
+    double phi1 = M_PI + a.GetAzimuth();
+    double phi2 = M_PI; // reference direction
+
+    // Convert the spherical coordinates of the boresight and the incoming ray
+    // to Cartesian coordinates
+    Vector p1(sin(theta1) * cos(phi1), sin(theta1) * sin(phi1), cos(theta1));
+    Vector p2(sin(theta2) * cos(phi2), sin(theta2) * sin(phi2), cos(theta2));
+
+    // Calculate the angle between the antenna boresight and the incoming ray
+    double theta = acos(p1 * p2);
+
+    double gain = 0;
+    if (theta == 0)
+    {
+        gain = m_maxGain;
+    }
+    // return value of std::arccos is in [0, PI] deg
+    else if (theta >= M_PI_2)
+    {
+        // This is an approximation. 3GPP TR 38.811 does not provide indications
+        // on the antenna field pattern outside its PI degrees FOV.
+        gain = m_minGain;
+    }
+    else // 0 < theta < |PI/2|
+    {
+        // 3GPP TR 38.811 v15.4.0, Section 6.4.1
+        double k = (2 * M_PI * m_operatingFrequencyHz) / C;
+        double kasintheta = k * m_apertureRadiusMeter * sin(theta);
+// If needed, fall back to Boost cyl_bessel_j
+#ifdef NEED_AND_HAVE_BOOST_BESSEL_FUNC
+        gain = boost::math::cyl_bessel_j(1, kasintheta) / kasintheta;
+// Otherwise, use the std implementation
+#else
+        gain = std::cyl_bessel_j(1, kasintheta) / kasintheta;
+#endif
+        gain = 10 * log10(4 * gain * gain) + m_maxGain;
+    }
+
+    return gain;
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/model/circular-aperture-antenna-model.h ns-3.42/src/antenna/model/circular-aperture-antenna-model.h
--- ns-3.41/src/antenna/model/circular-aperture-antenna-model.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/antenna/model/circular-aperture-antenna-model.h	2024-05-29 15:29:46.916073000 -0700
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2022 University of Padova, Dep. of Information Engineering, SIGNET lab.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mattia Sandri <mattia.sandri@unipd.it>
+ */
+
+#ifndef CIRCULAR_APERTURE_ANTENNA_MODEL_H
+#define CIRCULAR_APERTURE_ANTENNA_MODEL_H
+
+#include "antenna-model.h"
+
+#include <ns3/object.h>
+
+/**
+ * \file
+ * \ingroup antenna
+ * Class CircularApertureAntennaModel declaration
+ */
+
+namespace ns3
+{
+/**
+ * \brief Circular Aperture Antenna Model
+ *
+ * This class implements the circular aperture antenna as described in 3GPP 38.811 6.4.1
+ * https://www.3gpp.org/ftp/Specs/archive/38_series/38.811 without the cosine approximation, thanks
+ * to the Bessel functions introduced in C++17. Spherical coordinates are used, in particular of the
+ * azimuth and inclination angles. All working parameters can be set, namely: operating frequency,
+ * aperture radius, maximum and minimum gain.
+ * Since Clang libc++ does not support the Mathematical special functions (P0226R1) yet, this class
+ * falls back to Boost's implementation of cyl_bessel_j whenever the above standard library is in
+ * use. If neither is available in the host system, this class is not compiled.
+ */
+class CircularApertureAntennaModel : public AntennaModel
+{
+  public:
+    CircularApertureAntennaModel() = default;
+    ~CircularApertureAntennaModel() override = default;
+
+    /**
+     * Register this type.
+     * \return The object TypeId.
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * \brief Set the antenna aperture radius
+     *
+     * Sets the antenna operating frequency, asserting that
+     * the provided value is within the acceptable range [0, +inf[.
+     *
+     * \param aMeter the strictly positive antenna radius in meters
+     */
+    void SetApertureRadius(double aMeter);
+
+    /**
+     * \brief Return the antenna aperture radius
+     *
+     * \return the antenna radius in meters
+     */
+    double GetApertureRadius() const;
+
+    /**
+     * \brief Set the antenna operating frequency.
+     *
+     * Sets the antenna operating frequency, asserting that
+     * the provided value is within the acceptable range [0, +inf[.
+     *
+     * \param freqHz the strictly positive antenna operating frequency, in Hz
+     */
+    void SetOperatingFrequency(double freqHz);
+
+    /**
+     * \brief Return the antenna operating frequency
+     *
+     * \return the antenna operating frequency, in Hz
+     */
+    double GetOperatingFrequency() const;
+
+    /**
+     * \brief Set the antenna max gain
+     *
+     * \param gainDb the antenna max gain in dB
+     */
+    void SetMaxGain(double gainDb);
+
+    /**
+     * \brief Return the antenna max gain
+     *
+     * \return the antenna max gain in dB
+     */
+    double GetMaxGain() const;
+
+    /**
+     * \brief Set the antenna min gain
+     *
+     * \param gainDb the antenna min gain in dB
+     */
+    void SetMinGain(double gainDb);
+
+    /**
+     * \brief Return the antenna min gain
+     *
+     * \return the antenna min gain in dB
+     */
+    double GetMinGain() const;
+
+    /**
+     * \brief Get the gain in dB, using Bessel equation of first kind and first order.
+     *
+     * \param a the angle at which the gain need to be calculated with respect to the antenna
+     * bore sight
+     *
+     * \return the antenna gain at the specified Angles a
+     */
+    double GetGainDb(Angles a) override;
+
+  private:
+    double m_apertureRadiusMeter;  //!< antenna aperture radius in meters
+    double m_operatingFrequencyHz; //!< antenna operating frequency in Hz
+    double m_maxGain;              //!< antenna gain in dB towards the main orientation
+    double m_minGain;              //!< antenna min gain in dB
+};
+
+} // namespace ns3
+
+#endif // CIRCULAR_APERTURE_ANTENNA_MODEL_H
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/model/uniform-planar-array.cc ns-3.42/src/antenna/model/uniform-planar-array.cc
--- ns-3.41/src/antenna/model/uniform-planar-array.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/model/uniform-planar-array.cc	2024-05-29 15:29:46.916073000 -0700
@@ -212,10 +212,12 @@
 
     // convert the theta and phi angles from GCS to LCS using eq. 7.1-7 and 7.1-8 in 3GPP TR 38.901
     // NOTE we assume a fixed slant angle of 0 degrees
-    double cosIncl = cos(a.GetInclination());
-    double sinIncl = sin(a.GetInclination());
-    double cosAzim = cos(a.GetAzimuth() - m_alpha);
-    double sinAzim = sin(a.GetAzimuth() - m_alpha);
+    double inclination = a.GetInclination();
+    double azimuth = a.GetAzimuth();
+    double cosIncl = cos(inclination);
+    double sinIncl = sin(inclination);
+    double cosAzim = cos(azimuth - m_alpha);
+    double sinAzim = sin(azimuth - m_alpha);
     double thetaPrime = std::acos(m_cosBeta * cosIncl + m_sinBeta * cosAzim * sinIncl);
     double phiPrime =
         std::arg(std::complex<double>(m_cosBeta * sinIncl * cosAzim - m_sinBeta * cosIncl,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/gen-test-circular-aperture-antenna-reference-points.m ns-3.42/src/antenna/test/gen-test-circular-aperture-antenna-reference-points.m
--- ns-3.41/src/antenna/test/gen-test-circular-aperture-antenna-reference-points.m	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/antenna/test/gen-test-circular-aperture-antenna-reference-points.m	2024-05-29 15:29:46.916073000 -0700
@@ -0,0 +1,105 @@
+%{
+    Compute the antenna gain pattern of the reflector antenna with circular aperture
+    specified in the Sec. 6.4.1, 3GPP 38.811 v.15.4.0 and generate reference gain values
+    for the CircularApertureAntennaModelTest.
+%}
+clc; clearvars;
+
+%{
+    Consider two testing vectors, one with elevation fixed to 90 degrees and
+    varying azimuth, the other with azimuth fixed to 180 degrees and varying elevation.
+    The boresight direction, is (az, el) = (180 degrees, 90 degrees)
+%}
+az_test_fixed_el = 90:10:180;
+eL_test_fixed_az = 0:9:90;
+%  Uncomment line below and comment line below for the fixed elevation test
+[theta_vec, az_vec, el_vec] = theta_vec_from_sph_coord_vecs(az_test_fixed_el, 90);
+%  Uncomment line above and comment line below for the fixed azimuth test
+%[theta_vec, az_vec, el_vec] = theta_vec_from_sph_coord_vecs(180, eL_test_fixed_az);
+
+%{
+ The theta angle which represents the input of the pattern formula is
+ computed as theta = arccos(<p1, p2>), where p_i = sin(theta_i) *
+ cos(phi_i), sin(theta_i) * sin(phi_i), cos(theta_i). The default
+ boresight is (phi1 (az), theta1(el)) = (180deg, 90deg)
+%}
+
+%{
+    3GPP specifies the antenna gain only for |theta| < 90 degrees.
+    The gain outside of this region is approximated as min_gain_dB
+%}
+min_gain_dB = -50;
+
+max_gain_dB = 0;
+c=physconst('LightSpeed');
+f=28e9; % operating frequency
+k=2*pi*f/c; % wave number
+a=10*c/f; % radius antenna aperture
+arg_vec=k*a*sind(theta_vec);
+pattern=besselj(1, arg_vec)./arg_vec;
+pattern= 4*(abs(pattern).^2);
+
+% Manually set gain for theta = 0
+where_arg_zero=find(~theta_vec);
+pattern(where_arg_zero)=1;
+gain_dB=10*log10(pattern) + max_gain_dB;
+
+% Manually set gain to minimum gain for |theta| >= 90 degrees
+where_arg_outside_pattern_domain = find(abs(theta_vec) >= 90);
+gain_dB(where_arg_outside_pattern_domain)=min_gain_dB;
+
+%{
+    Plot and output the C++ code which defines the reference vector of data points.
+    Test points are assumed to be encoded as C++ structs
+%}
+scatter(theta_vec, gain_dB);
+out_str = ns3_output_from_vecs(az_vec, el_vec, gain_dB, max_gain_dB, min_gain_dB, a, f);
+
+
+function theta = theta_from_sph_coord(phi1, theta1)
+%    theta_from_sph_coord Computes theta (the input of the radiation pattern formula)
+%    from the azimuth and elevation angles with resepct to boresight.
+%    phi1 the azimuth with respect to boresight
+%    theta1 the elevation angle with respect to boresight
+
+    p1 = [sind(theta1)*cosd(phi1), sind(theta1)*sind(phi1), cosd(theta1)];
+    % p2, i.e., the boresight direction, is phi1 (az), theta1(el)) =
+    % (180deg, 90deg)
+    theta2 = 90; phi2 = 180;
+    p2 = [sind(theta2)*cosd(phi2), sind(theta2)*sind(phi2), cosd(theta2)];
+    theta = acosd(dot(p1,p2));
+end
+
+function [theta_vec, az_vec, el_vec] = theta_vec_from_sph_coord_vecs(az_vec, el_vec)
+%    theta_vec_from_sph_coord_vecs Computes the vectors of thetas
+%    (the inputs of the radiation pattern formula)
+%    from vectors of azimuth and elevation angles with resepct to boresight.
+%    phi1 the vector of azimuths with respect to boresight
+%    theta1 the vector of elevation angles with respect to boresight
+    if size(az_vec, 2) > 1
+        el_vec = repelem(el_vec, size(az_vec, 2));
+    elseif size(el_vec, 2) > 1
+        az_vec = repelem(az_vec, size(el_vec, 2));
+    end
+    theta_vec = arrayfun(@theta_from_sph_coord, az_vec, el_vec);
+end
+
+function out_str = ns3_output_from_vecs(az_vec, el_vec, gain_dB_vec, max_gain, min_gain, a, f)
+%    ns3_output_from_vecs Outputs the reference gain values
+%    as a vector of vectors.
+%    The entries of the inner vectors, representing a single test point,
+%    represent: (gain at boresight (dB), gain outside the 3GPP pattern region (dB),
+%    aperture (meters), carrier frequency (Hz), test azimuth (degrees),
+%    test elevation angle (degrees), reference antenna gain (dB))
+    out_str = '';
+    for i=1:size(el_vec, 2)
+        out_str = [out_str, '{', ...
+                            num2str(max_gain), ',', ...
+                            num2str(min_gain), ',', ...
+                            num2str(a), ',', ...
+                            num2str(f), ',', ...
+                            num2str(az_vec(i) - 180), ',', ...
+                            num2str(el_vec(i)), ',', ...
+                            num2str(gain_dB_vec(i)), '},'];
+    end
+end
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-angles.cc ns-3.42/src/antenna/test/test-angles.cc
--- ns-3.41/src/antenna/test/test-angles.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/test/test-angles.cc	2024-05-29 15:29:46.916073000 -0700
@@ -296,227 +296,234 @@
 };
 
 AnglesTestSuite::AnglesTestSuite()
-    : TestSuite("angles", UNIT)
+    : TestSuite("angles", Type::UNIT)
 {
     AddTestCase(new OneVectorConstructorTestCase(Vector(1, 0, 0), Angles(0, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(-1, 0, 0), Angles(M_PI, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, 1, 0), Angles(M_PI_2, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, -1, 0), Angles(-M_PI_2, M_PI_2)),
-                TestCase::QUICK);
-    AddTestCase(new OneVectorConstructorTestCase(Vector(0, 0, 1), Angles(0, 0)), TestCase::QUICK);
+                TestCase::Duration::QUICK);
+    AddTestCase(new OneVectorConstructorTestCase(Vector(0, 0, 1), Angles(0, 0)),
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, 0, -1), Angles(0, M_PI)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new OneVectorConstructorTestCase(Vector(2, 0, 0), Angles(0, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(-2, 0, 0), Angles(M_PI, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, 2, 0), Angles(M_PI_2, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, -2, 0), Angles(-M_PI_2, M_PI_2)),
-                TestCase::QUICK);
-    AddTestCase(new OneVectorConstructorTestCase(Vector(0, 0, 2), Angles(0, 0)), TestCase::QUICK);
+                TestCase::Duration::QUICK);
+    AddTestCase(new OneVectorConstructorTestCase(Vector(0, 0, 2), Angles(0, 0)),
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, 0, -2), Angles(0, M_PI)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new OneVectorConstructorTestCase(Vector(1, 0, 1), Angles(0, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(1, 0, -1), Angles(0, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(1, 1, 0), Angles(M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(1, -1, 0), Angles(-M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(-1, 0, 1), Angles(M_PI, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(-1, 0, -1), Angles(M_PI, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(-1, 1, 0), Angles(3 * M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(-1, -1, 0), Angles(-3 * M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, 1, 1), Angles(M_PI_2, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, 1, -1), Angles(M_PI_2, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, -1, 1), Angles(-M_PI_2, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OneVectorConstructorTestCase(Vector(0, -1, -1), Angles(-M_PI_2, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(
         new OneVectorConstructorTestCase(Vector(1, 1, std::sqrt(2)), Angles(M_PI_4, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new OneVectorConstructorTestCase(Vector(1, 1, -std::sqrt(2)), Angles(M_PI_4, 3 * M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new OneVectorConstructorTestCase(Vector(1, -1, std::sqrt(2)), Angles(-M_PI_4, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new OneVectorConstructorTestCase(Vector(-1, 1, std::sqrt(2)), Angles(3 * M_PI_4, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(1, 0, 0), Vector(0, 0, 0), Angles(0, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(-1, 0, 0), Vector(0, 0, 0), Angles(M_PI, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(0, 1, 0), Vector(0, 0, 0), Angles(M_PI_2, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, -1, 0),
                                                   Vector(0, 0, 0),
                                                   Angles(-M_PI_2, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, 0, 1), Vector(0, 0, 0), Angles(0, 0)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(0, 0, -1), Vector(0, 0, 0), Angles(0, M_PI)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(2, 0, 0), Vector(0, 0, 0), Angles(0, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(-2, 0, 0), Vector(0, 0, 0), Angles(M_PI, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(0, 2, 0), Vector(0, 0, 0), Angles(M_PI_2, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, -2, 0),
                                                   Vector(0, 0, 0),
                                                   Angles(-M_PI_2, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, 0, 2), Vector(0, 0, 0), Angles(0, 0)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(0, 0, -2), Vector(0, 0, 0), Angles(0, M_PI)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(1, 0, 1), Vector(0, 0, 0), Angles(0, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(1, 0, -1), Vector(0, 0, 0), Angles(0, 3 * M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(1, 1, 0), Vector(0, 0, 0), Angles(M_PI_4, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(1, -1, 0),
                                                   Vector(0, 0, 0),
                                                   Angles(-M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(-1, 0, 1), Vector(0, 0, 0), Angles(M_PI, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(-1, 0, -1),
                                                   Vector(0, 0, 0),
                                                   Angles(M_PI, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(-1, 1, 0),
                                                   Vector(0, 0, 0),
                                                   Angles(3 * M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(-1, -1, 0),
                                                   Vector(0, 0, 0),
                                                   Angles(-3 * M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(0, 1, 1), Vector(0, 0, 0), Angles(M_PI_2, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, 1, -1),
                                                   Vector(0, 0, 0),
                                                   Angles(M_PI_2, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, -1, 1),
                                                   Vector(0, 0, 0),
                                                   Angles(-M_PI_2, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, -1, -1),
                                                   Vector(0, 0, 0),
                                                   Angles(-M_PI_2, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(1, 1, std::sqrt(2)),
                                                   Vector(0, 0, 0),
                                                   Angles(M_PI_4, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(1, 1, -std::sqrt(2)),
                                                   Vector(0, 0, 0),
                                                   Angles(M_PI_4, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(1, -1, std::sqrt(2)),
                                                   Vector(0, 0, 0),
                                                   Angles(-M_PI_4, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(-1, 1, std::sqrt(2)),
                                                   Vector(0, 0, 0),
                                                   Angles(3 * M_PI_4, M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(3, 2, 2), Vector(2, 2, 2), Angles(0, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(1, 2, 2), Vector(2, 2, 2), Angles(M_PI, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(2, 3, 2), Vector(2, 2, 2), Angles(M_PI_2, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(-1, 2, 2),
                                                   Vector(-1, 3, 2),
                                                   Angles(-M_PI_2, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(4, -2, 7), Vector(4, -2, 6), Angles(0, 0)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(0, -5, -1), Vector(0, -5, 0), Angles(0, M_PI)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(-2, 2, -1), Vector(-4, 2, -1), Angles(0, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(2, 2, 0), Vector(4, 2, 0), Angles(M_PI, M_PI_2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(
         new TwoVectorsConstructorTestCase(Vector(-1, 4, 4), Vector(-2, 4, 3), Angles(0, M_PI_4)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0, -2, -6),
                                                   Vector(-1, -2, -5),
                                                   Angles(0, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(77, 3, 43),
                                                   Vector(78, 2, 43),
                                                   Angles(3 * M_PI_4, M_PI_2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(24, -2, -6 - std::sqrt(2)),
                                                   Vector(23, -3, -6),
                                                   Angles(M_PI_4, 3 * M_PI_4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TwoVectorsConstructorTestCase(Vector(0.5, 11.45, std::sqrt(2) - 1),
                                                   Vector(-0.5, 12.45, -1),
                                                   Angles(-M_PI_4, M_PI_4)),
-                TestCase::QUICK);
-    AddTestCase(new WrapToRangeTestCase(WrapTo180, -180, 180), TestCase::QUICK);
-    AddTestCase(new WrapToRangeTestCase(WrapToPi, -M_PI, M_PI), TestCase::QUICK);
-    AddTestCase(new WrapToRangeTestCase(WrapTo360, 0, 360), TestCase::QUICK);
-    AddTestCase(new WrapToRangeTestCase(WrapTo2Pi, 0, 2 * M_PI), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, -182.2, 177.8), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, -179, -179), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, 181, -179), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, 360.6, 0.6), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, -182.8, 177.2), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, -179, 181), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, 181, 181), TestCase::QUICK);
-    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, 360.2, 0.2), TestCase::QUICK);
+                TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeTestCase(WrapTo180, -180, 180), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeTestCase(WrapToPi, -M_PI, M_PI), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeTestCase(WrapTo360, 0, 360), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeTestCase(WrapTo2Pi, 0, 2 * M_PI), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, -182.2, 177.8),
+                TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, -179, -179),
+                TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, 181, -179), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo180, 360.6, 0.6),
+                TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, -182.8, 177.2),
+                TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, -179, 181), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, 181, 181), TestCase::Duration::QUICK);
+    AddTestCase(new WrapToRangeFunctionalTestCase(WrapTo360, 360.2, 0.2),
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-circular-aperture-antenna.cc ns-3.42/src/antenna/test/test-circular-aperture-antenna.cc
--- ns-3.41/src/antenna/test/test-circular-aperture-antenna.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/antenna/test/test-circular-aperture-antenna.cc	2024-05-29 15:29:46.916073000 -0700
@@ -0,0 +1,242 @@
+/*
+ *   Copyright (c) 2023 University of Padova, Dep. of Information Engineering, SIGNET lab.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2 as
+ *   published by the Free Software Foundation;
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ns3/circular-aperture-antenna-model.h"
+#include "ns3/double.h"
+#include "ns3/log.h"
+#include "ns3/pointer.h"
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+#include "ns3/uinteger.h"
+#include "ns3/uniform-planar-array.h"
+
+#include <cmath>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("TestCircularApertureAntennaModel");
+
+/**
+ * \ingroup antenna-tests
+ *
+ * \brief CircularApertureAntennaModel Test Case
+ *
+ * Note: Since Clang libc++ does not support the Mathematical special functions (P0226R1) yet, this
+ * class falls back to Boost's implementation of cyl_bessel_j whenever the above standard library is
+ * in use. If neither is available in the host system, this class is not compiled.
+ */
+class CircularApertureAntennaModelTestCase : public TestCase
+{
+  public:
+    CircularApertureAntennaModelTestCase();
+
+    /**
+     * \brief Description of a single test point
+     *
+     * Description of a test point, which is characterized
+     * by the CircularApertureAntennaModel parameters,
+     * the directions towards which the antenna gain
+     * is to be tested, and the expected gain value.
+     */
+    struct TestPoint
+    {
+        /**
+         * @brief Constructor
+         *
+         * @param antennaMaxGainDb the antenna maximum possible gain [dB]
+         * @param antennaMinGainDb the antenna minimum possible gain [dB]
+         * @param antennaCircularApertureRadius the radius of the parabolic aperture [m]
+         * @param operatingFrequency operating frequency [Hz]
+         * @param testAzimuth test azimuth [rad]
+         * @param testInclination test inclination [rad]
+         * @param expectedGain the expected gain value [dB]
+         */
+        TestPoint(double antennaMaxGainDb,
+                  double antennaMinGainDb,
+                  double antennaCircularApertureRadius,
+                  double operatingFrequency,
+                  double testAzimuth,
+                  double testInclination,
+                  double expectedGain)
+            : m_antennaMaxGainDb(antennaMaxGainDb),
+              m_antennaMinGainDb(antennaMinGainDb),
+              m_antennaCircularApertureRadius(antennaCircularApertureRadius),
+              m_operatingFrequency(operatingFrequency),
+              m_testAzimuth(DegreesToRadians(testAzimuth)),
+              m_testInclination(DegreesToRadians(testInclination)),
+              m_expectedGain(expectedGain)
+        {
+        }
+
+        double m_antennaMaxGainDb;              ///< the antenna maximum possible gain [dB]
+        double m_antennaMinGainDb;              ///< the antenna minimum possible gain [dB]
+        double m_antennaCircularApertureRadius; ///< the radius of the parabolic aperture [m]
+        double m_operatingFrequency;            ///< operating frequency [Hz]
+        double m_testAzimuth;                   ///< test azimuth [rad]
+        double m_testInclination;               ///< test inclination [rad]
+        double m_expectedGain;                  ///< the expected gain value [dB]
+    };
+
+    /**
+     * Generate a string containing all relevant parameters
+     * \param testPoint the parameter configuration to be tested
+     * \return the string containing all relevant parameters
+     */
+    static std::string BuildNameString(TestPoint testPoint);
+
+    /**
+     * Test the antenna gain for a specific parameter configuration,
+     * by comparing the antenna gain obtained using CircularApertureAntennaModel::GetGainDb
+     * and the one obtained using MATLAB.
+     *
+     * \param testPoint the parameter configuration to be tested
+     */
+    void TestAntennaGain(TestPoint testPoint);
+
+  private:
+    /**
+     * Run the test
+     */
+    void DoRun() override;
+};
+
+CircularApertureAntennaModelTestCase::CircularApertureAntennaModelTestCase()
+    : TestCase("Creating CircularApertureAntennaModelTestCase")
+{
+}
+
+std::string
+CircularApertureAntennaModelTestCase::BuildNameString(TestPoint testPoint)
+{
+    std::ostringstream oss;
+    oss << " Maximum gain=" << testPoint.m_antennaMaxGainDb << "dB"
+        << " minimum gain=" << testPoint.m_antennaMinGainDb << "dB"
+        << ", antenna aperture radius=" << testPoint.m_antennaCircularApertureRadius << "m"
+        << ", frequency" << testPoint.m_operatingFrequency << "Hz"
+        << ", test inclination=" << RadiansToDegrees(testPoint.m_testInclination) << " deg"
+        << ", test azimuth=" << RadiansToDegrees(testPoint.m_testAzimuth) << " deg";
+    return oss.str();
+}
+
+void
+CircularApertureAntennaModelTestCase::TestAntennaGain(TestPoint testPoint)
+{
+    Ptr<CircularApertureAntennaModel> antenna =
+        CreateObjectWithAttributes<CircularApertureAntennaModel>(
+            "AntennaMaxGainDb",
+            DoubleValue(testPoint.m_antennaMaxGainDb),
+            "AntennaMinGainDb",
+            DoubleValue(testPoint.m_antennaMinGainDb),
+            "AntennaCircularApertureRadius",
+            DoubleValue(testPoint.m_antennaCircularApertureRadius),
+            "OperatingFrequency",
+            DoubleValue(testPoint.m_operatingFrequency));
+
+    Ptr<UniformPlanarArray> upa =
+        CreateObjectWithAttributes<UniformPlanarArray>("AntennaElement",
+                                                       PointerValue(antenna),
+                                                       "NumColumns",
+                                                       UintegerValue(1),
+                                                       "NumRows",
+                                                       UintegerValue(1));
+
+    auto [fieldPhi, fieldTheta] =
+        upa->GetElementFieldPattern(Angles(testPoint.m_testAzimuth, testPoint.m_testInclination),
+                                    0);
+    // Compute the antenna gain as the squared sum of the field pattern components
+    double gainDb = 10 * log10(fieldPhi * fieldPhi + fieldTheta * fieldTheta);
+    auto log = BuildNameString(testPoint);
+    NS_LOG_INFO(log);
+    NS_TEST_EXPECT_MSG_EQ_TOL(gainDb, testPoint.m_expectedGain, 0.1, log);
+}
+
+void
+CircularApertureAntennaModelTestCase::DoRun()
+{
+    // Vector of test points
+    std::vector<TestPoint> testPoints = {
+        // MaxGainDb  MinGainDb  Radius (m)  Freq (Hz)   Azimuth (deg)  Incl (deg)  ExpGain (dB)
+        // Test invariant: gain always equal to max gain at boresight (inclination 90, azimuth = 0)
+        // for different frequency
+        {30, -30, 0.5, 2e9, 0, 90, 30},
+        {30, -30, 2, 20e9, 0, 90, 30},
+        // Test invariant: gain always equal to max gain at boresight (inclination 90, azimuth = 0)
+        // for different max gain
+        {20, -30, 0.5, 2e9, 0, 90, 20},
+        {10, -30, 2, 20e9, 0, 90, 10},
+        // Test invariant: gain always equal to min gain outside of |theta| < 90 deg
+        // for different frequency
+        {30, -100, 0.5, 2e9, 0, 0, -100},
+        {30, -100, 2, 20e9, 0, 0, -100},
+        // Test invariant: gain always equal to min gain outside of |theta| < 90 deg
+        // for different orientations
+        {30, -100, 0.5, 2e9, 180, 90, -100},
+        {30, -100, 2, 20e9, -180, 90, -100},
+        // Fixed elevation to boresight (90deg) and azimuth varying in [-90, 0] deg with steps of 10
+        // degrees
+        {0, -50, 0.10707, 28000000000, -90, 90, -50},
+        {0, -50, 0.10707, 28000000000, -80, 90, -49.8022},
+        {0, -50, 0.10707, 28000000000, -70, 90, -49.1656},
+        {0, -50, 0.10707, 28000000000, -60, 90, -60.9132},
+        {0, -50, 0.10707, 28000000000, -50, 90, -59.2368},
+        {0, -50, 0.10707, 28000000000, -40, 90, -44.6437},
+        {0, -50, 0.10707, 28000000000, -30, 90, -43.9686},
+        {0, -50, 0.10707, 28000000000, -20, 90, -36.3048},
+        {0, -50, 0.10707, 28000000000, -10, 90, -30.5363},
+        {0, -50, 0.10707, 28000000000, 0, 90, 0},
+        // Fixed azimuth to boresight (0 deg) and azimuth varying in [0, 90] deg with steps of 9
+        // degrees
+        {0, -50, 0.10707, 28e9, 0, 0, -50},
+        {0, -50, 0.10707, 28e9, 0, 9, -49.7256},
+        {0, -50, 0.10707, 28e9, 0, 18, -52.9214},
+        {0, -50, 0.10707, 28e9, 0, 27, -48.6077},
+        {0, -50, 0.10707, 28e9, 0, 36, -60.684},
+        {0, -50, 0.10707, 28e9, 0, 45, -55.1468},
+        {0, -50, 0.10707, 28e9, 0, 54, -42.9648},
+        {0, -50, 0.10707, 28e9, 0, 63, -45.6472},
+        {0, -50, 0.10707, 28e9, 0, 72, -48.6378},
+        {0, -50, 0.10707, 28e9, 0, 81, -35.1613},
+        {0, -50, 0.10707, 28e9, 0, 90, 0}};
+
+    // Call TestAntennaGain on each test point
+    for (auto& point : testPoints)
+    {
+        TestAntennaGain(point);
+    }
+}
+
+/**
+ * \ingroup antenna-tests
+ *
+ * \brief UniformPlanarArray Test Suite
+ */
+class CircularApertureAntennaModelTestSuite : public TestSuite
+{
+  public:
+    CircularApertureAntennaModelTestSuite();
+};
+
+CircularApertureAntennaModelTestSuite::CircularApertureAntennaModelTestSuite()
+    : TestSuite("circular-aperture-antenna-test", Type::UNIT)
+{
+    AddTestCase(new CircularApertureAntennaModelTestCase());
+}
+
+static CircularApertureAntennaModelTestSuite staticCircularApertureAntennaModelTestSuiteInstance;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-cosine-antenna.cc ns-3.42/src/antenna/test/test-cosine-antenna.cc
--- ns-3.41/src/antenna/test/test-cosine-antenna.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/test/test-cosine-antenna.cc	2024-05-29 15:29:46.916073000 -0700
@@ -151,7 +151,7 @@
 };
 
 CosineAntennaModelTestSuite::CosineAntennaModelTestSuite()
-    : TestSuite("cosine-antenna-model", UNIT)
+    : TestSuite("cosine-antenna-model", Type::UNIT)
 {
     // to calculate the azimut angle offset for a given gain in db:
     // phideg = (2*acos(10^(targetgaindb/(20*n))))*180/pi
@@ -166,77 +166,77 @@
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(100), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(150), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(180), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-180), DegreesToRadians(90)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // test positive orientation
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(60), DegreesToRadians(90)),
@@ -245,77 +245,77 @@
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(150), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(160), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(210), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(240), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-40), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-120), DegreesToRadians(90)),
                                                60,
                                                60,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // test negative orientation and different beamwidths
     // with a 100 deg beamwidth, gain is -20dB at +- 117.47 degrees from boresight
@@ -325,21 +325,21 @@
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-200), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(-32.531), DegreesToRadians(90)),
                                        100,
@@ -347,7 +347,7 @@
                                        0,
                                        -20,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(92.531), DegreesToRadians(90)),
                                        100,
@@ -355,42 +355,42 @@
                                        0,
                                        -20,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(60), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // with a 150 deg beamwidth, gain is -10dB at +- 124.93 degrees from boresight, and -20dB at +-
     // 155.32 degrees from boresight
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(90)),
@@ -399,21 +399,21 @@
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(135), DegreesToRadians(90)),
                                                150,
                                                -150,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-75), DegreesToRadians(90)),
                                                150,
                                                -150,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(85.070), DegreesToRadians(90)),
                                        150,
@@ -421,7 +421,7 @@
                                        0,
                                        -10,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(-25.070), DegreesToRadians(90)),
                                        150,
@@ -429,7 +429,7 @@
                                        0,
                                        -10,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(5.3230), DegreesToRadians(90)),
                                        150,
@@ -437,7 +437,7 @@
                                        0,
                                        -20,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(54.677), DegreesToRadians(90)),
                                        150,
@@ -445,21 +445,21 @@
                                        0,
                                        -20,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                                150,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(20), DegreesToRadians(90)),
                                                150,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // test flat beam, with beamwidth=360 deg
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                360,
@@ -467,35 +467,35 @@
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(180), DegreesToRadians(90)),
                                                360,
                                                0,
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-180), DegreesToRadians(90)),
                                                360,
                                                0,
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(0)),
                                                360,
                                                0,
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(180)),
                                                360,
                                                0,
                                                0,
                                                0,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // test maxGain
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(90)),
@@ -504,63 +504,63 @@
                                                10,
                                                10,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                                60,
                                                0,
                                                22,
                                                19,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                                60,
                                                0,
                                                -4,
                                                -7,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(90)),
                                                60,
                                                0,
                                                10,
                                                -10,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                60,
                                                0,
                                                -20,
                                                -40,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(100), DegreesToRadians(90)),
                                                60,
                                                0,
                                                40,
                                                20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                2,
                                                2,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                4,
                                                1,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-200), DegreesToRadians(90)),
                                                100,
                                                -150,
                                                -1,
                                                -4,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // test elevation angle
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(60)),
@@ -569,56 +569,56 @@
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(60)),
                                                60,
                                                0,
                                                0,
                                                -6,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(60)),
                                                60,
                                                0,
                                                0,
                                                -6,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(60)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-180), DegreesToRadians(60)),
                                                60,
                                                0,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(60), DegreesToRadians(120)),
                                                60,
                                                60,
                                                0,
                                                -3,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(120)),
                                                60,
                                                60,
                                                0,
                                                -6,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(120)),
                                                60,
                                                60,
                                                0,
                                                -6,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(-120), DegreesToRadians(120)),
                                        60,
@@ -626,7 +626,7 @@
                                        0,
                                        -20,
                                        LESSTHAN),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(140)),
                                        100,
@@ -634,7 +634,7 @@
                                        0,
                                        -3,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(140)),
                                        100,
@@ -642,7 +642,7 @@
                                        0,
                                        -6,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new CosineAntennaModelTestCase(Angles(DegreesToRadians(-200), DegreesToRadians(140)),
                                        100,
@@ -650,77 +650,77 @@
                                        0,
                                        -6,
                                        EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(140)),
                                                100,
                                                -150,
                                                0,
                                                -20,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(60)),
                                                60,
                                                0,
                                                10,
                                                7,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(60)),
                                                60,
                                                0,
                                                22,
                                                16,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(60)),
                                                60,
                                                0,
                                                -4,
                                                -10,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(60)),
                                                60,
                                                0,
                                                10,
                                                -13,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(60)),
                                                60,
                                                0,
                                                -20,
                                                -43,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(100), DegreesToRadians(60)),
                                                60,
                                                0,
                                                40,
                                                17,
                                                LESSTHAN),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(40)),
                                                100,
                                                -150,
                                                2,
                                                -1,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(40)),
                                                100,
                                                -150,
                                                4,
                                                -2,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CosineAntennaModelTestCase(Angles(DegreesToRadians(-200), DegreesToRadians(40)),
                                                100,
                                                -150,
                                                -1,
                                                -7,
                                                EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-degrees-radians.cc ns-3.42/src/antenna/test/test-degrees-radians.cc
--- ns-3.41/src/antenna/test/test-degrees-radians.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/test/test-degrees-radians.cc	2024-05-29 15:29:46.916073000 -0700
@@ -138,23 +138,23 @@
 };
 
 DegreesRadiansTestSuite::DegreesRadiansTestSuite()
-    : TestSuite("degrees-radians", UNIT)
+    : TestSuite("degrees-radians", Type::UNIT)
 {
-    AddTestCase(new DegreesToRadiansTestCase(0, 0), TestCase::QUICK);
-    AddTestCase(new DegreesToRadiansTestCase(90, M_PI_2), TestCase::QUICK);
-    AddTestCase(new DegreesToRadiansTestCase(180, M_PI), TestCase::QUICK);
-    AddTestCase(new DegreesToRadiansTestCase(270, M_PI + M_PI_2), TestCase::QUICK);
-    AddTestCase(new DegreesToRadiansTestCase(360, M_PI + M_PI), TestCase::QUICK);
-    AddTestCase(new DegreesToRadiansTestCase(-90, -M_PI_2), TestCase::QUICK);
-    AddTestCase(new DegreesToRadiansTestCase(810, 4.5 * M_PI), TestCase::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(0, 0), TestCase::Duration::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(90, M_PI_2), TestCase::Duration::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(180, M_PI), TestCase::Duration::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(270, M_PI + M_PI_2), TestCase::Duration::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(360, M_PI + M_PI), TestCase::Duration::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(-90, -M_PI_2), TestCase::Duration::QUICK);
+    AddTestCase(new DegreesToRadiansTestCase(810, 4.5 * M_PI), TestCase::Duration::QUICK);
 
-    AddTestCase(new RadiansToDegreesTestCase(0, 0), TestCase::QUICK);
-    AddTestCase(new RadiansToDegreesTestCase(M_PI_2, 90), TestCase::QUICK);
-    AddTestCase(new RadiansToDegreesTestCase(M_PI, 180), TestCase::QUICK);
-    AddTestCase(new RadiansToDegreesTestCase(M_PI + M_PI_2, 270), TestCase::QUICK);
-    AddTestCase(new RadiansToDegreesTestCase(M_PI + M_PI, 360), TestCase::QUICK);
-    AddTestCase(new RadiansToDegreesTestCase(-M_PI_2, -90), TestCase::QUICK);
-    AddTestCase(new RadiansToDegreesTestCase(4.5 * M_PI, 810), TestCase::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(0, 0), TestCase::Duration::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(M_PI_2, 90), TestCase::Duration::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(M_PI, 180), TestCase::Duration::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(M_PI + M_PI_2, 270), TestCase::Duration::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(M_PI + M_PI, 360), TestCase::Duration::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(-M_PI_2, -90), TestCase::Duration::QUICK);
+    AddTestCase(new RadiansToDegreesTestCase(4.5 * M_PI, 810), TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-isotropic-antenna.cc ns-3.42/src/antenna/test/test-isotropic-antenna.cc
--- ns-3.41/src/antenna/test/test-isotropic-antenna.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/test/test-isotropic-antenna.cc	2024-05-29 15:29:46.916073000 -0700
@@ -94,17 +94,23 @@
 };
 
 IsotropicAntennaModelTestSuite::IsotropicAntennaModelTestSuite()
-    : TestSuite("isotropic-antenna-model", UNIT)
+    : TestSuite("isotropic-antenna-model", Type::UNIT)
 {
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(0, 0), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(0, M_PI), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(0, M_PI_2), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI, 0), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI, M_PI), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI, M_PI_2), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, 0), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, M_PI), 0.0), TestCase::QUICK);
-    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, M_PI_2), 0.0), TestCase::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(0, 0), 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(0, M_PI), 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(0, M_PI_2), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI, 0), 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI, M_PI), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI, M_PI_2), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, 0), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, M_PI), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new IsotropicAntennaModelTestCase(Angles(M_PI_2, M_PI_2), 0.0),
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-parabolic-antenna.cc ns-3.42/src/antenna/test/test-parabolic-antenna.cc
--- ns-3.41/src/antenna/test/test-parabolic-antenna.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/test/test-parabolic-antenna.cc	2024-05-29 15:29:46.916073000 -0700
@@ -152,7 +152,7 @@
 };
 
 ParabolicAntennaModelTestSuite::ParabolicAntennaModelTestSuite()
-    : TestSuite("parabolic-antenna-model", UNIT)
+    : TestSuite("parabolic-antenna-model", Type::UNIT)
 {
     // with a 60 deg beamwidth, gain is -20dB at +-77.460 degrees from boresight
     //                                                                         phi, theta,
@@ -166,7 +166,7 @@
                                                   20,
                                                   0,
                                                   EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                           60,
@@ -174,7 +174,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                           60,
@@ -182,7 +182,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(90)),
                                           60,
@@ -190,7 +190,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                           60,
@@ -198,7 +198,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(100), DegreesToRadians(90)),
                                           60,
@@ -206,7 +206,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(150), DegreesToRadians(90)),
                                           60,
@@ -214,7 +214,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(180), DegreesToRadians(90)),
                                           60,
@@ -222,7 +222,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(90)),
                                           60,
@@ -230,7 +230,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(90)),
                                           60,
@@ -238,7 +238,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-180), DegreesToRadians(90)),
                                           60,
@@ -246,7 +246,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // with a 60 deg beamwidth, gain is -10dB at +-54.772 degrees from boresight
     // test positive orientation
@@ -257,7 +257,7 @@
                                           10,
                                           0,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                           60,
@@ -265,7 +265,7 @@
                                           10,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                           60,
@@ -273,7 +273,7 @@
                                           10,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                           60,
@@ -281,7 +281,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(150), DegreesToRadians(90)),
                                           60,
@@ -289,7 +289,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(160), DegreesToRadians(90)),
                                           60,
@@ -297,7 +297,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(210), DegreesToRadians(90)),
                                           60,
@@ -305,7 +305,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(240), DegreesToRadians(90)),
                                           60,
@@ -313,7 +313,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-40), DegreesToRadians(90)),
                                           60,
@@ -321,7 +321,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(90)),
                                           60,
@@ -329,7 +329,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-120), DegreesToRadians(90)),
                                           60,
@@ -337,7 +337,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // test negative orientation and different beamwidths
     // with a 80 deg beamwidth, gain is -20dB at +- 73.030 degrees from boresight
@@ -348,7 +348,7 @@
                                           10,
                                           0,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-110), DegreesToRadians(90)),
                                           80,
@@ -356,7 +356,7 @@
                                           10,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-190), DegreesToRadians(90)),
                                           80,
@@ -364,7 +364,7 @@
                                           10,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-70), DegreesToRadians(90)),
                                           80,
@@ -372,7 +372,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(92), DegreesToRadians(90)),
                                           80,
@@ -380,7 +380,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(90)),
                                           80,
@@ -388,14 +388,14 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                   80,
                                                   -150,
                                                   10,
                                                   -10,
                                                   EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(60), DegreesToRadians(90)),
                                           80,
@@ -403,7 +403,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                           80,
@@ -411,7 +411,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(90)),
                                           80,
@@ -419,7 +419,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // test elevation angle
     AddTestCase(new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(88)),
@@ -428,7 +428,7 @@
                                                   20,
                                                   0,
                                                   EQUAL),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(88)),
                                           60,
@@ -436,7 +436,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(88)),
                                           60,
@@ -444,7 +444,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-90), DegreesToRadians(88)),
                                           60,
@@ -452,7 +452,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-180), DegreesToRadians(88)),
                                           60,
@@ -460,7 +460,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(60), DegreesToRadians(93)),
                                           60,
@@ -468,7 +468,7 @@
                                           20,
                                           0,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(93)),
                                           60,
@@ -476,7 +476,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(93)),
                                           60,
@@ -484,7 +484,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-120), DegreesToRadians(93)),
                                           60,
@@ -492,7 +492,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(93)),
                                           100,
@@ -500,7 +500,7 @@
                                           10,
                                           0,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(93)),
                                           100,
@@ -508,7 +508,7 @@
                                           10,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-200), DegreesToRadians(93)),
                                           100,
@@ -516,7 +516,7 @@
                                           10,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(93)),
                                           100,
@@ -524,7 +524,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(90), DegreesToRadians(80.5)),
                                           100,
@@ -532,7 +532,7 @@
                                           10,
                                           -10,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(0), DegreesToRadians(80.5)),
                                           60,
@@ -540,7 +540,7 @@
                                           20,
                                           0,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(30), DegreesToRadians(80.5)),
                                           60,
@@ -548,7 +548,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-30), DegreesToRadians(80.5)),
                                           60,
@@ -556,7 +556,7 @@
                                           20,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(100), DegreesToRadians(80.5)),
                                           60,
@@ -564,7 +564,7 @@
                                           20,
                                           -20,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-150), DegreesToRadians(80.5)),
                                           100,
@@ -572,7 +572,7 @@
                                           30,
                                           0,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-100), DegreesToRadians(80.5)),
                                           100,
@@ -580,7 +580,7 @@
                                           30,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new ParabolicAntennaModelTestCase(Angles(DegreesToRadians(-200), DegreesToRadians(80.5)),
                                           100,
@@ -588,7 +588,7 @@
                                           30,
                                           -3,
                                           EQUAL),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/antenna/test/test-uniform-planar-array.cc ns-3.42/src/antenna/test/test-uniform-planar-array.cc
--- ns-3.41/src/antenna/test/test-uniform-planar-array.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/antenna/test/test-uniform-planar-array.cc	2024-05-29 15:29:46.916073000 -0700
@@ -215,7 +215,7 @@
 };
 
 UniformPlanarArrayTestSuite::UniformPlanarArrayTestSuite()
-    : TestSuite("uniform-planar-array-test", UNIT)
+    : TestSuite("uniform-planar-array-test", Type::UNIT)
 {
     Ptr<AntennaModel> isotropic = CreateObject<IsotropicAntennaModel>();
     Ptr<AntennaModel> tgpp = CreateObject<ThreeGppAntennaModel>();
@@ -233,7 +233,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                0.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -243,7 +243,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -253,7 +253,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -263,7 +263,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(-90), DegreesToRadians(90)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -273,7 +273,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(180), DegreesToRadians(90)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -283,7 +283,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(-180), DegreesToRadians(90)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -293,7 +293,7 @@
                                                DegreesToRadians(45),
                                                Angles(DegreesToRadians(0), DegreesToRadians(135)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -303,7 +303,7 @@
                                                DegreesToRadians(-45),
                                                Angles(DegreesToRadians(0), DegreesToRadians(45)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -313,7 +313,7 @@
                                                DegreesToRadians(90),
                                                Angles(DegreesToRadians(0), DegreesToRadians(180)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                1,
                                                1,
@@ -323,7 +323,7 @@
                                                DegreesToRadians(-90),
                                                Angles(DegreesToRadians(0), DegreesToRadians(0)),
                                                8.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // linear array
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
@@ -335,7 +335,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                18.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                10,
                                                1,
@@ -345,7 +345,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                18.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                10,
                                                1,
@@ -355,7 +355,7 @@
                                                DegreesToRadians(45),
                                                Angles(DegreesToRadians(0), DegreesToRadians(135)),
                                                18.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // planar array
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
@@ -367,7 +367,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(0), DegreesToRadians(90)),
                                                28.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                10,
                                                10,
@@ -377,7 +377,7 @@
                                                DegreesToRadians(0),
                                                Angles(DegreesToRadians(90), DegreesToRadians(90)),
                                                28.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new UniformPlanarArrayTestCase(tgpp,
                                                10,
                                                10,
@@ -387,7 +387,7 @@
                                                DegreesToRadians(45),
                                                Angles(DegreesToRadians(0), DegreesToRadians(135)),
                                                28.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 static UniformPlanarArrayTestSuite staticUniformPlanarArrayTestSuiteInstance;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/aodv/examples/aodv.cc ns-3.42/src/aodv/examples/aodv.cc
--- ns-3.41/src/aodv/examples/aodv.cc	2024-02-09 14:44:07.849789600 -0800
+++ ns-3.42/src/aodv/examples/aodv.cc	2024-05-29 15:29:46.916073000 -0700
@@ -34,6 +34,12 @@
 using namespace ns3;
 
 /**
+ * \defgroup aodv-examples AODV Examples
+ * \ingroup aodv
+ * \ingroup examples
+ */
+
+/**
  * \ingroup aodv-examples
  * \ingroup examples
  * \brief Test script.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/aodv/model/aodv-routing-protocol.cc ns-3.42/src/aodv/model/aodv-routing-protocol.cc
--- ns-3.41/src/aodv/model/aodv-routing-protocol.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/aodv/model/aodv-routing-protocol.cc	2024-05-29 15:29:46.916073000 -0700
@@ -1685,33 +1685,24 @@
     RoutingTableEntry toDst;
     if (m_routingTable.LookupRoute(dst, toDst))
     {
-        /*
-         * The existing entry is updated only in the following circumstances:
-         * (i) the sequence number in the routing table is marked as invalid in route table entry.
-         */
-        if (!toDst.GetValidSeqNo())
-        {
-            m_routingTable.Update(newEntry);
-        }
-        // (ii)the Destination Sequence Number in the RREP is greater than the node's copy of the
-        // destination sequence number and the known value is valid,
-        else if ((int32_t(rrepHeader.GetDstSeqno()) - int32_t(toDst.GetSeqNo())) > 0)
-        {
-            m_routingTable.Update(newEntry);
-        }
-        else
-        {
+        // The existing entry is updated only in the following circumstances:
+        if (
+            // (i) the sequence number in the routing table is marked as invalid in route table
+            // entry.
+            (!toDst.GetValidSeqNo()) ||
+
+            // (ii) the Destination Sequence Number in the RREP is greater than the node's copy of
+            // the destination sequence number and the known value is valid,
+            ((int32_t(rrepHeader.GetDstSeqno()) - int32_t(toDst.GetSeqNo())) > 0) ||
+
             // (iii) the sequence numbers are the same, but the route is marked as inactive.
-            if ((rrepHeader.GetDstSeqno() == toDst.GetSeqNo()) && (toDst.GetFlag() != VALID))
-            {
-                m_routingTable.Update(newEntry);
-            }
-            // (iv)  the sequence numbers are the same, and the New Hop Count is smaller than the
+            (rrepHeader.GetDstSeqno() == toDst.GetSeqNo() && toDst.GetFlag() != VALID) ||
+
+            // (iv) the sequence numbers are the same, and the New Hop Count is smaller than the
             // hop count in route table entry.
-            else if ((rrepHeader.GetDstSeqno() == toDst.GetSeqNo()) && (hop < toDst.GetHop()))
-            {
-                m_routingTable.Update(newEntry);
-            }
+            (rrepHeader.GetDstSeqno() == toDst.GetSeqNo() && hop < toDst.GetHop()))
+        {
+            m_routingTable.Update(newEntry);
         }
     }
     else
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/aodv/test/aodv-id-cache-test-suite.cc ns-3.42/src/aodv/test/aodv-id-cache-test-suite.cc
--- ns-3.41/src/aodv/test/aodv-id-cache-test-suite.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/aodv/test/aodv-id-cache-test-suite.cc	2024-05-29 15:29:46.920073000 -0700
@@ -118,9 +118,9 @@
 {
   public:
     IdCacheTestSuite()
-        : TestSuite("aodv-routing-id-cache", UNIT)
+        : TestSuite("aodv-routing-id-cache", Type::UNIT)
     {
-        AddTestCase(new IdCacheTest, TestCase::QUICK);
+        AddTestCase(new IdCacheTest, TestCase::Duration::QUICK);
     }
 } g_idCacheTestSuite; ///< the test suite
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/aodv/test/aodv-regression.cc ns-3.42/src/aodv/test/aodv-regression.cc
--- ns-3.41/src/aodv/test/aodv-regression.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/aodv/test/aodv-regression.cc	2024-05-29 15:29:46.920073000 -0700
@@ -52,17 +52,18 @@
 {
   public:
     AodvRegressionTestSuite()
-        : TestSuite("routing-aodv-regression", SYSTEM)
+        : TestSuite("routing-aodv-regression", Type::SYSTEM)
     {
         SetDataDir(NS_TEST_SOURCEDIR);
         // General RREQ-RREP-RRER test case
-        AddTestCase(new ChainRegressionTest("aodv-chain-regression-test"), TestCase::QUICK);
+        AddTestCase(new ChainRegressionTest("aodv-chain-regression-test"),
+                    TestCase::Duration::QUICK);
         // \bugid{606} test case, should crash if bug is not fixed
         AddTestCase(new ChainRegressionTest("bug-606-test", Seconds(10), 3, Seconds(1)),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         // \bugid{772} UDP test case
         AddTestCase(new Bug772ChainTest("udp-chain-test", "ns3::UdpSocketFactory", Seconds(3), 10),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 } g_aodvRegressionTestSuite; ///< the test suite
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/aodv/test/aodv-test-suite.cc ns-3.42/src/aodv/test/aodv-test-suite.cc
--- ns-3.41/src/aodv/test/aodv-test-suite.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/aodv/test/aodv-test-suite.cc	2024-05-29 15:29:46.920073000 -0700
@@ -739,18 +739,18 @@
 {
   public:
     AodvTestSuite()
-        : TestSuite("routing-aodv", UNIT)
+        : TestSuite("routing-aodv", Type::UNIT)
     {
-        AddTestCase(new NeighborTest, TestCase::QUICK);
-        AddTestCase(new TypeHeaderTest, TestCase::QUICK);
-        AddTestCase(new RreqHeaderTest, TestCase::QUICK);
-        AddTestCase(new RrepHeaderTest, TestCase::QUICK);
-        AddTestCase(new RrepAckHeaderTest, TestCase::QUICK);
-        AddTestCase(new RerrHeaderTest, TestCase::QUICK);
-        AddTestCase(new QueueEntryTest, TestCase::QUICK);
-        AddTestCase(new AodvRqueueTest, TestCase::QUICK);
-        AddTestCase(new AodvRtableEntryTest, TestCase::QUICK);
-        AddTestCase(new AodvRtableTest, TestCase::QUICK);
+        AddTestCase(new NeighborTest, TestCase::Duration::QUICK);
+        AddTestCase(new TypeHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new RreqHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new RrepHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new RrepAckHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new RerrHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new QueueEntryTest, TestCase::Duration::QUICK);
+        AddTestCase(new AodvRqueueTest, TestCase::Duration::QUICK);
+        AddTestCase(new AodvRtableEntryTest, TestCase::Duration::QUICK);
+        AddTestCase(new AodvRtableTest, TestCase::Duration::QUICK);
     }
 } g_aodvTestSuite; ///< the test suite
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/aodv/test/loopback.cc ns-3.42/src/aodv/test/loopback.cc
--- ns-3.41/src/aodv/test/loopback.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/aodv/test/loopback.cc	2024-05-29 15:29:46.920073000 -0700
@@ -197,11 +197,11 @@
 {
   public:
     AodvLoopbackTestSuite()
-        : TestSuite("routing-aodv-loopback", SYSTEM)
+        : TestSuite("routing-aodv-loopback", Type::SYSTEM)
     {
         SetDataDir(NS_TEST_SOURCEDIR);
         // UDP Echo loopback test case
-        AddTestCase(new LoopbackTestCase(), TestCase::QUICK);
+        AddTestCase(new LoopbackTestCase(), TestCase::Duration::QUICK);
     }
 } g_aodvLoopbackTestSuite; ///< the test suite
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/bulk-send-helper.cc ns-3.42/src/applications/helper/bulk-send-helper.cc
--- ns-3.41/src/applications/helper/bulk-send-helper.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/bulk-send-helper.cc	2024-05-29 15:29:46.920073000 -0700
@@ -21,59 +21,16 @@
 
 #include "bulk-send-helper.h"
 
-#include "ns3/inet-socket-address.h"
-#include "ns3/names.h"
-#include "ns3/packet-socket-address.h"
-#include "ns3/string.h"
+#include <ns3/string.h>
 
 namespace ns3
 {
 
-BulkSendHelper::BulkSendHelper(std::string protocol, Address address)
+BulkSendHelper::BulkSendHelper(const std::string& protocol, const Address& address)
+    : ApplicationHelper("ns3::BulkSendApplication")
 {
-    m_factory.SetTypeId("ns3::BulkSendApplication");
     m_factory.Set("Protocol", StringValue(protocol));
     m_factory.Set("Remote", AddressValue(address));
 }
 
-void
-BulkSendHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-BulkSendHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-BulkSendHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-BulkSendHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-BulkSendHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<Application>();
-    node->AddApplication(app);
-
-    return app;
-}
-
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/bulk-send-helper.h ns-3.42/src/applications/helper/bulk-send-helper.h
--- ns-3.41/src/applications/helper/bulk-send-helper.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/bulk-send-helper.h	2024-05-29 15:29:46.920073000 -0700
@@ -22,15 +22,7 @@
 #ifndef BULK_SEND_HELPER_H
 #define BULK_SEND_HELPER_H
 
-#include "ns3/address.h"
-#include "ns3/application-container.h"
-#include "ns3/attribute.h"
-#include "ns3/net-device.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
-
-#include <stdint.h>
-#include <string>
+#include <ns3/application-helper.h>
 
 namespace ns3
 {
@@ -40,7 +32,7 @@
  * \brief A helper to make it easier to instantiate an ns3::BulkSendApplication
  * on a set of nodes.
  */
-class BulkSendHelper
+class BulkSendHelper : public ApplicationHelper
 {
   public:
     /**
@@ -53,58 +45,9 @@
      * \param address the address of the remote node to send traffic
      *        to.
      */
-    BulkSendHelper(std::string protocol, Address address);
-
-    /**
-     * Helper function used to set the underlying application attributes,
-     * _not_ the socket attributes.
-     *
-     * \param name the name of the application attribute to set
-     * \param value the value of the application attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * Install an ns3::BulkSendApplication on each node of the input container
-     * configured with all the attributes set with SetAttribute.
-     *
-     * \param c NodeContainer of the set of nodes on which an BulkSendApplication
-     * will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-    /**
-     * Install an ns3::BulkSendApplication on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an BulkSendApplication will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Install an ns3::BulkSendApplication on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param nodeName The node on which an BulkSendApplication will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-  private:
-    /**
-     * Install an ns3::BulkSendApplication on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an BulkSendApplication will be installed.
-     * \returns Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-
-    ObjectFactory m_factory; //!< Object factory.
+    BulkSendHelper(const std::string& protocol, const Address& address);
 };
 
 } // namespace ns3
 
-#endif /* ON_OFF_HELPER_H */
+#endif /* BULK_SEND_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/on-off-helper.cc ns-3.42/src/applications/helper/on-off-helper.cc
--- ns-3.41/src/applications/helper/on-off-helper.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/on-off-helper.cc	2024-05-29 15:29:46.920073000 -0700
@@ -16,88 +16,24 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
 #include "on-off-helper.h"
 
-#include "ns3/data-rate.h"
-#include "ns3/inet-socket-address.h"
-#include "ns3/names.h"
-#include "ns3/onoff-application.h"
-#include "ns3/packet-socket-address.h"
-#include "ns3/random-variable-stream.h"
-#include "ns3/string.h"
-#include "ns3/uinteger.h"
+#include <ns3/onoff-application.h>
+#include <ns3/string.h>
+#include <ns3/uinteger.h>
 
 namespace ns3
 {
 
-OnOffHelper::OnOffHelper(std::string protocol, Address address)
+OnOffHelper::OnOffHelper(const std::string& protocol, const Address& address)
+    : ApplicationHelper("ns3::OnOffApplication")
 {
-    m_factory.SetTypeId("ns3::OnOffApplication");
     m_factory.Set("Protocol", StringValue(protocol));
     m_factory.Set("Remote", AddressValue(address));
 }
 
 void
-OnOffHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-OnOffHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-OnOffHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-OnOffHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-OnOffHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<Application>();
-    node->AddApplication(app);
-
-    return app;
-}
-
-int64_t
-OnOffHelper::AssignStreams(NodeContainer c, int64_t stream)
-{
-    int64_t currentStream = stream;
-    Ptr<Node> node;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        node = (*i);
-        for (uint32_t j = 0; j < node->GetNApplications(); j++)
-        {
-            Ptr<OnOffApplication> onoff = DynamicCast<OnOffApplication>(node->GetApplication(j));
-            if (onoff)
-            {
-                currentStream += onoff->AssignStreams(currentStream);
-            }
-        }
-    }
-    return (currentStream - stream);
-}
-
-void
 OnOffHelper::SetConstantRate(DataRate dataRate, uint32_t packetSize)
 {
     m_factory.Set("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1000]"));
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/on-off-helper.h ns-3.42/src/applications/helper/on-off-helper.h
--- ns-3.41/src/applications/helper/on-off-helper.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/on-off-helper.h	2024-05-29 15:29:46.920073000 -0700
@@ -16,31 +16,24 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
 #ifndef ON_OFF_HELPER_H
 #define ON_OFF_HELPER_H
 
-#include "ns3/address.h"
-#include "ns3/application-container.h"
-#include "ns3/attribute.h"
-#include "ns3/net-device.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
-#include "ns3/onoff-application.h"
+#include <ns3/application-helper.h>
+#include <ns3/data-rate.h>
 
 #include <stdint.h>
-#include <string>
 
 namespace ns3
 {
 
-class DataRate;
-
 /**
  * \ingroup onoff
  * \brief A helper to make it easier to instantiate an ns3::OnOffApplication
  * on a set of nodes.
  */
-class OnOffHelper
+class OnOffHelper : public ApplicationHelper
 {
   public:
     /**
@@ -53,15 +46,7 @@
      * \param address the address of the remote node to send traffic
      *        to.
      */
-    OnOffHelper(std::string protocol, Address address);
-
-    /**
-     * Helper function used to set the underlying application attributes.
-     *
-     * \param name the name of the application attribute to set
-     * \param value the value of the application attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
+    OnOffHelper(const std::string& protocol, const Address& address);
 
     /**
      * Helper function to set a constant rate source.  Equivalent to
@@ -72,59 +57,6 @@
      * \param packetSize size in bytes of the packet payloads generated
      */
     void SetConstantRate(DataRate dataRate, uint32_t packetSize = 512);
-
-    /**
-     * Install an ns3::OnOffApplication on each node of the input container
-     * configured with all the attributes set with SetAttribute.
-     *
-     * \param c NodeContainer of the set of nodes on which an OnOffApplication
-     * will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-    /**
-     * Install an ns3::OnOffApplication on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an OnOffApplication will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Install an ns3::OnOffApplication on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param nodeName The node on which an OnOffApplication will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-    /**
-     * Assign a fixed random variable stream number to the random variables
-     * used by this model.  Return the number of streams (possibly zero) that
-     * have been assigned.  The Install() method should have previously been
-     * called by the user.
-     *
-     * \param stream first stream index to use
-     * \param c NodeContainer of the set of nodes for which the OnOffApplication
-     *          should be modified to use a fixed stream
-     * \return the number of stream indices assigned by this helper
-     */
-    int64_t AssignStreams(NodeContainer c, int64_t stream);
-
-  private:
-    /**
-     * Install an ns3::OnOffApplication on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an OnOffApplication will be installed.
-     * \returns Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-
-    ObjectFactory m_factory; //!< Object factory.
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/packet-sink-helper.cc ns-3.42/src/applications/helper/packet-sink-helper.cc
--- ns-3.41/src/applications/helper/packet-sink-helper.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/packet-sink-helper.cc	2024-05-29 15:29:46.920073000 -0700
@@ -19,58 +19,16 @@
 
 #include "packet-sink-helper.h"
 
-#include "ns3/inet-socket-address.h"
-#include "ns3/names.h"
-#include "ns3/string.h"
+#include <ns3/string.h>
 
 namespace ns3
 {
 
-PacketSinkHelper::PacketSinkHelper(std::string protocol, Address address)
+PacketSinkHelper::PacketSinkHelper(const std::string& protocol, const Address& address)
+    : ApplicationHelper("ns3::PacketSink")
 {
-    m_factory.SetTypeId("ns3::PacketSink");
     m_factory.Set("Protocol", StringValue(protocol));
     m_factory.Set("Local", AddressValue(address));
 }
 
-void
-PacketSinkHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-PacketSinkHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-PacketSinkHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-PacketSinkHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-PacketSinkHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<Application>();
-    node->AddApplication(app);
-
-    return app;
-}
-
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/packet-sink-helper.h ns-3.42/src/applications/helper/packet-sink-helper.h
--- ns-3.41/src/applications/helper/packet-sink-helper.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/packet-sink-helper.h	2024-05-29 15:29:46.920073000 -0700
@@ -16,13 +16,11 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
 #ifndef PACKET_SINK_HELPER_H
 #define PACKET_SINK_HELPER_H
 
-#include "ns3/application-container.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
+#include <ns3/application-helper.h>
 
 namespace ns3
 {
@@ -32,7 +30,7 @@
  * \brief A helper to make it easier to instantiate an ns3::PacketSinkApplication
  * on a set of nodes.
  */
-class PacketSinkHelper
+class PacketSinkHelper : public ApplicationHelper
 {
   public:
     /**
@@ -45,54 +43,7 @@
      * \param address the address of the sink,
      *
      */
-    PacketSinkHelper(std::string protocol, Address address);
-
-    /**
-     * Helper function used to set the underlying application attributes.
-     *
-     * \param name the name of the application attribute to set
-     * \param value the value of the application attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * Install an ns3::PacketSinkApplication on each node of the input container
-     * configured with all the attributes set with SetAttribute.
-     *
-     * \param c NodeContainer of the set of nodes on which a PacketSinkApplication
-     * will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-    /**
-     * Install an ns3::PacketSinkApplication on each node of the input container
-     * configured with all the attributes set with SetAttribute.
-     *
-     * \param node The node on which a PacketSinkApplication will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Install an ns3::PacketSinkApplication on each node of the input container
-     * configured with all the attributes set with SetAttribute.
-     *
-     * \param nodeName The name of the node on which a PacketSinkApplication will be installed.
-     * \returns Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-  private:
-    /**
-     * Install an ns3::PacketSink on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an PacketSink will be installed.
-     * \returns Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-    ObjectFactory m_factory; //!< Object factory.
+    PacketSinkHelper(const std::string& protocol, const Address& address);
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/three-gpp-http-helper.cc ns-3.42/src/applications/helper/three-gpp-http-helper.cc
--- ns-3.41/src/applications/helper/three-gpp-http-helper.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/three-gpp-http-helper.cc	2024-05-29 15:29:46.920073000 -0700
@@ -25,105 +25,23 @@
 
 #include "three-gpp-http-helper.h"
 
-#include <ns3/names.h>
-
 namespace ns3
 {
 
 // 3GPP HTTP CLIENT HELPER /////////////////////////////////////////////////////////
 
 ThreeGppHttpClientHelper::ThreeGppHttpClientHelper(const Address& address)
+    : ApplicationHelper("ns3::ThreeGppHttpClient")
 {
-    m_factory.SetTypeId("ns3::ThreeGppHttpClient");
     m_factory.Set("RemoteServerAddress", AddressValue(address));
 }
 
-void
-ThreeGppHttpClientHelper::SetAttribute(const std::string& name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-ThreeGppHttpClientHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-ThreeGppHttpClientHelper::Install(const std::string& nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-ThreeGppHttpClientHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-ThreeGppHttpClientHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<Application>();
-    node->AddApplication(app);
-
-    return app;
-}
-
 // HTTP SERVER HELPER /////////////////////////////////////////////////////////
 
 ThreeGppHttpServerHelper::ThreeGppHttpServerHelper(const Address& address)
+    : ApplicationHelper("ns3::ThreeGppHttpServer")
 {
-    m_factory.SetTypeId("ns3::ThreeGppHttpServer");
     m_factory.Set("LocalAddress", AddressValue(address));
 }
 
-void
-ThreeGppHttpServerHelper::SetAttribute(const std::string& name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-ThreeGppHttpServerHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-ThreeGppHttpServerHelper::Install(const std::string& nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-ThreeGppHttpServerHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-ThreeGppHttpServerHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<Application>();
-    node->AddApplication(app);
-
-    return app;
-}
-
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/three-gpp-http-helper.h ns-3.42/src/applications/helper/three-gpp-http-helper.h
--- ns-3.41/src/applications/helper/three-gpp-http-helper.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/three-gpp-http-helper.h	2024-05-29 15:29:46.920073000 -0700
@@ -26,9 +26,7 @@
 #ifndef THREE_GPP_HTTP_HELPER_H
 #define THREE_GPP_HTTP_HELPER_H
 
-#include <ns3/application-container.h>
-#include <ns3/node-container.h>
-#include <ns3/object-factory.h>
+#include <ns3/application-helper.h>
 
 namespace ns3
 {
@@ -37,7 +35,7 @@
  * \ingroup applications
  * Helper to make it easier to instantiate an ThreeGppHttpClient on a set of nodes.
  */
-class ThreeGppHttpClientHelper
+class ThreeGppHttpClientHelper : public ApplicationHelper
 {
   public:
     /**
@@ -46,61 +44,13 @@
      * \param address The address of the remote server node to send traffic to.
      */
     ThreeGppHttpClientHelper(const Address& address);
-
-    /**
-     * Helper function used to set the underlying application attributes, but
-     * *not* the socket attributes.
-     * \param name The name of the application attribute to set.
-     * \param value The value of the application attribute to set.
-     */
-    void SetAttribute(const std::string& name, const AttributeValue& value);
-
-    /**
-     * Install a ThreeGppHttpClient on each node of the input container configured with
-     * all the attributes set with SetAttribute().
-     * \param c NodeContainer of the set of nodes on which an ThreeGppHttpClient
-     *          will be installed.
-     * \return Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-    /**
-     * Install a ThreeGppHttpClient on each node of the input container
-     * configured with all the attributes set with SetAttribute().
-     * \param node The node on which an ThreeGppHttpClient will be installed.
-     * \return Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Install a ThreeGppHttpClient on each node of the input container
-     * configured with all the attributes set with SetAttribute().
-     * \param nodeName The name of the node on which an ThreeGppHttpClient
-     *                 will be installed.
-     * \return Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(const std::string& nodeName) const;
-
-  private:
-    /**
-     * \internal
-     * Install a ThreeGppHttpClient on the node configured with all the
-     * attributes set with SetAttribute().
-     * \param node The node on which an ThreeGppHttpClient will be installed.
-     * \return Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-
-    /// Used to instantiate an ThreeGppHttpClient instance.
-    ObjectFactory m_factory;
-
 }; // end of `class ThreeGppHttpClientHelper`
 
 /**
  * \ingroup http
  * Helper to make it easier to instantiate an ThreeGppHttpServer on a set of nodes.
  */
-class ThreeGppHttpServerHelper
+class ThreeGppHttpServerHelper : public ApplicationHelper
 {
   public:
     /**
@@ -109,54 +59,6 @@
      * \param address The address of the server.
      */
     ThreeGppHttpServerHelper(const Address& address);
-
-    /**
-     * Helper function used to set the underlying application attributes, but
-     * *not* the socket attributes.
-     * \param name The name of the application attribute to set.
-     * \param value The value of the application attribute to set.
-     */
-    void SetAttribute(const std::string& name, const AttributeValue& value);
-
-    /**
-     * Install an ThreeGppHttpServer on each node of the input container
-     * configured with all the attributes set with SetAttribute().
-     * \param c NodeContainer of the set of nodes on which an ThreeGppHttpServer
-     *              will be installed.
-     * \return Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-    /**
-     * Install an ThreeGppHttpServer on each node of the input container
-     * configured with all the attributes set with SetAttribute().
-     * \param node The node on which an ThreeGppHttpServer will be installed.
-     * \return Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Install an ThreeGppHttpServer on each node of the input container
-     * configured with all the attributes set with SetAttribute().
-     * \param nodeName The name of the node on which an ThreeGppHttpServer
-     *                             will be installed.
-     * \return Container of Ptr to the applications installed.
-     */
-    ApplicationContainer Install(const std::string& nodeName) const;
-
-  private:
-    /**
-     * \internal
-     * Install an ThreeGppHttpServer on the node configured with all the
-     * attributes set with SetAttribute().
-     * \param node The node on which an ThreeGppHttpServer will be installed.
-     * \return Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-
-    /// Used to instantiate a ThreeGppHttpServer instance.
-    ObjectFactory m_factory;
-
 }; // end of `class ThreeGppHttpServerHelper`
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/udp-client-server-helper.cc ns-3.42/src/applications/helper/udp-client-server-helper.cc
--- ns-3.41/src/applications/helper/udp-client-server-helper.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/udp-client-server-helper.cc	2024-05-29 15:29:46.920073000 -0700
@@ -16,131 +16,61 @@
  *
  * Author: Mohamed Amine Ismail <amine.ismail@sophia.inria.fr>
  */
+
 #include "udp-client-server-helper.h"
 
-#include "ns3/string.h"
-#include "ns3/udp-client.h"
-#include "ns3/udp-server.h"
-#include "ns3/udp-trace-client.h"
-#include "ns3/uinteger.h"
+#include <ns3/string.h>
+#include <ns3/uinteger.h>
 
 namespace ns3
 {
 
 UdpServerHelper::UdpServerHelper()
+    : ApplicationHelper(UdpServer::GetTypeId())
 {
-    m_factory.SetTypeId(UdpServer::GetTypeId());
 }
 
 UdpServerHelper::UdpServerHelper(uint16_t port)
+    : UdpServerHelper()
 {
-    m_factory.SetTypeId(UdpServer::GetTypeId());
     SetAttribute("Port", UintegerValue(port));
 }
 
-void
-UdpServerHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-UdpServerHelper::Install(NodeContainer c)
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        Ptr<Node> node = *i;
-
-        m_server = m_factory.Create<UdpServer>();
-        node->AddApplication(m_server);
-        apps.Add(m_server);
-    }
-    return apps;
-}
-
-Ptr<UdpServer>
-UdpServerHelper::GetServer()
-{
-    return m_server;
-}
-
 UdpClientHelper::UdpClientHelper()
+    : ApplicationHelper(UdpClient::GetTypeId())
 {
-    m_factory.SetTypeId(UdpClient::GetTypeId());
-}
-
-UdpClientHelper::UdpClientHelper(Address address, uint16_t port)
-{
-    m_factory.SetTypeId(UdpClient::GetTypeId());
-    SetAttribute("RemoteAddress", AddressValue(address));
-    SetAttribute("RemotePort", UintegerValue(port));
 }
 
-UdpClientHelper::UdpClientHelper(Address address)
+UdpClientHelper::UdpClientHelper(const Address& address)
+    : UdpClientHelper()
 {
-    m_factory.SetTypeId(UdpClient::GetTypeId());
     SetAttribute("RemoteAddress", AddressValue(address));
 }
 
-void
-UdpClientHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-UdpClientHelper::Install(NodeContainer c)
+UdpClientHelper::UdpClientHelper(const Address& address, uint16_t port)
+    : UdpClientHelper(address)
 {
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        Ptr<Node> node = *i;
-        Ptr<UdpClient> client = m_factory.Create<UdpClient>();
-        node->AddApplication(client);
-        apps.Add(client);
-    }
-    return apps;
+    SetAttribute("RemotePort", UintegerValue(port));
 }
 
 UdpTraceClientHelper::UdpTraceClientHelper()
+    : ApplicationHelper(UdpTraceClient::GetTypeId())
 {
-    m_factory.SetTypeId(UdpTraceClient::GetTypeId());
 }
 
-UdpTraceClientHelper::UdpTraceClientHelper(Address address, uint16_t port, std::string filename)
+UdpTraceClientHelper::UdpTraceClientHelper(const Address& address, const std::string& filename)
+    : UdpTraceClientHelper()
 {
-    m_factory.SetTypeId(UdpTraceClient::GetTypeId());
     SetAttribute("RemoteAddress", AddressValue(address));
-    SetAttribute("RemotePort", UintegerValue(port));
     SetAttribute("TraceFilename", StringValue(filename));
 }
 
-UdpTraceClientHelper::UdpTraceClientHelper(Address address, std::string filename)
+UdpTraceClientHelper::UdpTraceClientHelper(const Address& address,
+                                           uint16_t port,
+                                           const std::string& filename)
+    : UdpTraceClientHelper(address, filename)
 {
-    m_factory.SetTypeId(UdpTraceClient::GetTypeId());
-    SetAttribute("RemoteAddress", AddressValue(address));
-    SetAttribute("TraceFilename", StringValue(filename));
-}
-
-void
-UdpTraceClientHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-UdpTraceClientHelper::Install(NodeContainer c)
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        Ptr<Node> node = *i;
-        Ptr<UdpTraceClient> client = m_factory.Create<UdpTraceClient>();
-        node->AddApplication(client);
-        apps.Add(client);
-    }
-    return apps;
+    SetAttribute("RemotePort", UintegerValue(port));
 }
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/udp-client-server-helper.h ns-3.42/src/applications/helper/udp-client-server-helper.h
--- ns-3.41/src/applications/helper/udp-client-server-helper.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/udp-client-server-helper.h	2024-05-29 15:29:46.920073000 -0700
@@ -16,15 +16,14 @@
  *
  * Author: Mohamed Amine Ismail <amine.ismail@sophia.inria.fr>
  */
+
 #ifndef UDP_CLIENT_SERVER_HELPER_H
 #define UDP_CLIENT_SERVER_HELPER_H
 
-#include "ns3/application-container.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
-#include "ns3/udp-client.h"
-#include "ns3/udp-server.h"
+#include <ns3/application-helper.h>
+#include <ns3/udp-client.h>
+#include <ns3/udp-server.h>
+#include <ns3/udp-trace-client.h>
 
 #include <stdint.h>
 
@@ -36,7 +35,7 @@
  *        and uses the information carried into their payload to compute
  *        delay and to determine if some packets are lost.
  */
-class UdpServerHelper
+class UdpServerHelper : public ApplicationHelper
 {
   public:
     /**
@@ -53,38 +52,6 @@
      * \param port The port the server will wait on for incoming packets
      */
     UdpServerHelper(uint16_t port);
-
-    /**
-     * Record an attribute to be set in each Application after it is is created.
-     *
-     * \param name the name of the attribute to set
-     * \param value the value of the attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * Create one UDP server application on each of the Nodes in the
-     * NodeContainer.
-     *
-     * \param c The nodes on which to create the Applications.  The nodes
-     *          are specified by a NodeContainer.
-     * \returns The applications created, one Application per Node in the
-     *          NodeContainer.
-     */
-    ApplicationContainer Install(NodeContainer c);
-
-    /**
-     * \brief Return the last created server.
-     *
-     * This function is mainly used for testing.
-     *
-     * \returns a Ptr to the last created server application
-     */
-    Ptr<UdpServer> GetServer();
-
-  private:
-    ObjectFactory m_factory; //!< Object factory.
-    Ptr<UdpServer> m_server; //!< The last created server application
 };
 
 /**
@@ -93,7 +60,7 @@
  *  a 32bit sequence number and a 64 bit time stamp.
  *
  */
-class UdpClientHelper
+class UdpClientHelper : public ApplicationHelper
 {
   public:
     /**
@@ -113,7 +80,7 @@
      * \param port The port number of the remote UDP server
      */
 
-    UdpClientHelper(Address ip, uint16_t port);
+    UdpClientHelper(const Address& ip, uint16_t port);
     /**
      *  Create UdpClientHelper which will make life easier for people trying
      * to set up simulations with udp-client-server. Use this variant with
@@ -123,27 +90,7 @@
      * \param addr The address of the remote UDP server
      */
 
-    UdpClientHelper(Address addr);
-
-    /**
-     * Record an attribute to be set in each Application after it is is created.
-     *
-     * \param name the name of the attribute to set
-     * \param value the value of the attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * \param c the nodes
-     *
-     * Create one UDP client application on each of the input nodes
-     *
-     * \returns the applications created, one application per input node.
-     */
-    ApplicationContainer Install(NodeContainer c);
-
-  private:
-    ObjectFactory m_factory; //!< Object factory.
+    UdpClientHelper(const Address& addr);
 };
 
 /**
@@ -158,7 +105,7 @@
  * \li -3- the third one indicates the time on which the frame was generated by the encoder
  * \li -4- the fourth one indicates the frame size in byte
  */
-class UdpTraceClientHelper
+class UdpTraceClientHelper : public ApplicationHelper
 {
   public:
     /**
@@ -178,7 +125,8 @@
      * \param port The port number of the remote UDP server
      * \param filename the file from which packet traces will be loaded
      */
-    UdpTraceClientHelper(Address ip, uint16_t port, std::string filename);
+    UdpTraceClientHelper(const Address& ip, uint16_t port, const std::string& filename = "");
+
     /**
      * Create UdpTraceClientHelper which will make life easier for people trying
      * to set up simulations with udp-client-server. Use this variant with
@@ -188,27 +136,7 @@
      * \param addr The address of the remote UDP server
      * \param filename the file from which packet traces will be loaded
      */
-    UdpTraceClientHelper(Address addr, std::string filename);
-
-    /**
-     * Record an attribute to be set in each Application after it is is created.
-     *
-     * \param name the name of the attribute to set
-     * \param value the value of the attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * \param c the nodes
-     *
-     * Create one UDP trace client application on each of the input nodes
-     *
-     * \returns the applications created, one application per input node.
-     */
-    ApplicationContainer Install(NodeContainer c);
-
-  private:
-    ObjectFactory m_factory; //!< Object factory.
+    UdpTraceClientHelper(const Address& addr, const std::string& filename = "");
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/udp-echo-helper.cc ns-3.42/src/applications/helper/udp-echo-helper.cc
--- ns-3.41/src/applications/helper/udp-echo-helper.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/udp-echo-helper.cc	2024-05-29 15:29:46.920073000 -0700
@@ -16,9 +16,9 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
 #include "udp-echo-helper.h"
 
-#include "ns3/names.h"
 #include "ns3/udp-echo-client.h"
 #include "ns3/udp-echo-server.h"
 #include "ns3/uinteger.h"
@@ -27,72 +27,26 @@
 {
 
 UdpEchoServerHelper::UdpEchoServerHelper(uint16_t port)
+    : ApplicationHelper(UdpEchoServer::GetTypeId())
 {
-    m_factory.SetTypeId(UdpEchoServer::GetTypeId());
     SetAttribute("Port", UintegerValue(port));
 }
 
-void
-UdpEchoServerHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-UdpEchoServerHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-UdpEchoServerHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-UdpEchoServerHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-UdpEchoServerHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<UdpEchoServer>();
-    node->AddApplication(app);
-
-    return app;
-}
-
-UdpEchoClientHelper::UdpEchoClientHelper(Address address, uint16_t port)
+UdpEchoClientHelper::UdpEchoClientHelper(const Address& address, uint16_t port)
+    : ApplicationHelper(UdpEchoClient::GetTypeId())
 {
-    m_factory.SetTypeId(UdpEchoClient::GetTypeId());
     SetAttribute("RemoteAddress", AddressValue(address));
     SetAttribute("RemotePort", UintegerValue(port));
 }
 
-UdpEchoClientHelper::UdpEchoClientHelper(Address address)
+UdpEchoClientHelper::UdpEchoClientHelper(const Address& address)
+    : ApplicationHelper(UdpEchoClient::GetTypeId())
 {
-    m_factory.SetTypeId(UdpEchoClient::GetTypeId());
     SetAttribute("RemoteAddress", AddressValue(address));
 }
 
 void
-UdpEchoClientHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-void
-UdpEchoClientHelper::SetFill(Ptr<Application> app, std::string fill)
+UdpEchoClientHelper::SetFill(Ptr<Application> app, const std::string& fill)
 {
     app->GetObject<UdpEchoClient>()->SetFill(fill);
 }
@@ -112,38 +66,4 @@
     app->GetObject<UdpEchoClient>()->SetFill(fill, fillLength, dataLength);
 }
 
-ApplicationContainer
-UdpEchoClientHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-UdpEchoClientHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-UdpEchoClientHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-UdpEchoClientHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Application> app = m_factory.Create<UdpEchoClient>();
-    node->AddApplication(app);
-
-    return app;
-}
-
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/helper/udp-echo-helper.h ns-3.42/src/applications/helper/udp-echo-helper.h
--- ns-3.41/src/applications/helper/udp-echo-helper.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/helper/udp-echo-helper.h	2024-05-29 15:29:46.920073000 -0700
@@ -16,14 +16,11 @@
  *
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
+
 #ifndef UDP_ECHO_HELPER_H
 #define UDP_ECHO_HELPER_H
 
-#include "ns3/application-container.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv6-address.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
+#include <ns3/application-helper.h>
 
 #include <stdint.h>
 
@@ -35,7 +32,7 @@
  * \brief Create a server application which waits for input UDP packets
  *        and sends them back to the original sender.
  */
-class UdpEchoServerHelper
+class UdpEchoServerHelper : public ApplicationHelper
 {
   public:
     /**
@@ -45,66 +42,13 @@
      * \param port The port the server will wait on for incoming packets
      */
     UdpEchoServerHelper(uint16_t port);
-
-    /**
-     * Record an attribute to be set in each Application after it is is created.
-     *
-     * \param name the name of the attribute to set
-     * \param value the value of the attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * Create a UdpEchoServerApplication on the specified Node.
-     *
-     * \param node The node on which to create the Application.  The node is
-     *             specified by a Ptr<Node>.
-     *
-     * \returns An ApplicationContainer holding the Application created,
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Create a UdpEchoServerApplication on specified node
-     *
-     * \param nodeName The node on which to create the application.  The node
-     *                 is specified by a node name previously registered with
-     *                 the Object Name Service.
-     *
-     * \returns An ApplicationContainer holding the Application created.
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-    /**
-     * \param c The nodes on which to create the Applications.  The nodes
-     *          are specified by a NodeContainer.
-     *
-     * Create one udp echo server application on each of the Nodes in the
-     * NodeContainer.
-     *
-     * \returns The applications created, one Application per Node in the
-     *          NodeContainer.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-  private:
-    /**
-     * Install an ns3::UdpEchoServer on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an UdpEchoServer will be installed.
-     * \returns Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-
-    ObjectFactory m_factory; //!< Object factory.
 };
 
 /**
  * \ingroup udpecho
  * \brief Create an application which sends a UDP packet and waits for an echo of this packet
  */
-class UdpEchoClientHelper
+class UdpEchoClientHelper : public ApplicationHelper
 {
   public:
     /**
@@ -115,7 +59,7 @@
      * \param ip The IP address of the remote udp echo server
      * \param port The port number of the remote udp echo server
      */
-    UdpEchoClientHelper(Address ip, uint16_t port);
+    UdpEchoClientHelper(const Address& ip, uint16_t port);
     /**
      * Create UdpEchoClientHelper which will make life easier for people trying
      * to set up simulations with echos. Use this variant with addresses that do
@@ -123,15 +67,7 @@
      *
      * \param addr The address of the remote udp echo server
      */
-    UdpEchoClientHelper(Address addr);
-
-    /**
-     * Record an attribute to be set in each Application after it is is created.
-     *
-     * \param name the name of the attribute to set
-     * \param value the value of the attribute to set
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
+    UdpEchoClientHelper(const Address& addr);
 
     /**
      * Given a pointer to a UdpEchoClient application, set the data fill of the
@@ -145,7 +81,7 @@
      * \param app Smart pointer to the application (real type must be UdpEchoClient).
      * \param fill The string to use as the actual echo data bytes.
      */
-    void SetFill(Ptr<Application> app, std::string fill);
+    void SetFill(Ptr<Application> app, const std::string& fill);
 
     /**
      * Given a pointer to a UdpEchoClient application, set the data fill of the
@@ -183,49 +119,6 @@
      * \param dataLength The desired length of the final echo data.
      */
     void SetFill(Ptr<Application> app, uint8_t* fill, uint32_t fillLength, uint32_t dataLength);
-
-    /**
-     * Create a udp echo client application on the specified node.  The Node
-     * is provided as a Ptr<Node>.
-     *
-     * \param node The Ptr<Node> on which to create the UdpEchoClientApplication.
-     *
-     * \returns An ApplicationContainer that holds a Ptr<Application> to the
-     *          application created
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Create a udp echo client application on the specified node.  The Node
-     * is provided as a string name of a Node that has been previously
-     * associated using the Object Name Service.
-     *
-     * \param nodeName The name of the node on which to create the UdpEchoClientApplication
-     *
-     * \returns An ApplicationContainer that holds a Ptr<Application> to the
-     *          application created
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-    /**
-     * \param c the nodes
-     *
-     * Create one udp echo client application on each of the input nodes
-     *
-     * \returns the applications created, one application per input node.
-     */
-    ApplicationContainer Install(NodeContainer c) const;
-
-  private:
-    /**
-     * Install an ns3::UdpEchoClient on the node configured with all the
-     * attributes set with SetAttribute.
-     *
-     * \param node The node on which an UdpEchoClient will be installed.
-     * \returns Ptr to the application installed.
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-    ObjectFactory m_factory; //!< Object factory.
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/bulk-send-application.cc ns-3.42/src/applications/model/bulk-send-application.cc
--- ns-3.41/src/applications/model/bulk-send-application.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/model/bulk-send-application.cc	2024-05-29 15:29:46.920073000 -0700
@@ -63,6 +63,12 @@
                           AddressValue(),
                           MakeAddressAccessor(&BulkSendApplication::m_local),
                           MakeAddressChecker())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&BulkSendApplication::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute("MaxBytes",
                           "The total number of bytes to send. "
                           "Once these bytes are sent, "
@@ -153,6 +159,8 @@
                            "In other words, use TCP instead of UDP.");
         }
 
+        NS_ABORT_MSG_IF(m_peer.IsInvalid(), "'Remote' attribute not properly set");
+
         if (!m_local.IsInvalid())
         {
             NS_ABORT_MSG_IF((Inet6SocketAddress::IsMatchingType(m_peer) &&
@@ -179,6 +187,10 @@
             NS_FATAL_ERROR("Failed to bind socket");
         }
 
+        if (InetSocketAddress::IsMatchingType(m_peer))
+        {
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
+        }
         m_socket->Connect(m_peer);
         m_socket->ShutdownRecv();
         m_socket->SetConnectCallback(MakeCallback(&BulkSendApplication::ConnectionSucceeded, this),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/bulk-send-application.h ns-3.42/src/applications/model/bulk-send-application.h
--- ns-3.41/src/applications/model/bulk-send-application.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/model/bulk-send-application.h	2024-05-29 15:29:46.920073000 -0700
@@ -111,9 +111,8 @@
     void DoDispose() override;
 
   private:
-    // inherited from Application base class.
-    void StartApplication() override; // Called at time specified by Start
-    void StopApplication() override;  // Called at time specified by Stop
+    void StartApplication() override;
+    void StopApplication() override;
 
     /**
      * \brief Send data until the L4 transmission buffer is full.
@@ -126,6 +125,7 @@
     Address m_peer;                      //!< Peer address
     Address m_local;                     //!< Local address to bind to
     bool m_connected;                    //!< True if connected
+    uint8_t m_tos;                       //!< The packets Type of Service
     uint32_t m_sendSize;                 //!< Size of data to send each time
     uint64_t m_maxBytes;                 //!< Limit total number of bytes sent
     uint64_t m_totBytes;                 //!< Total bytes sent so far
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/onoff-application.cc ns-3.42/src/applications/model/onoff-application.cc
--- ns-3.41/src/applications/model/onoff-application.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/model/onoff-application.cc	2024-05-29 15:29:46.920073000 -0700
@@ -79,6 +79,12 @@
                           AddressValue(),
                           MakeAddressAccessor(&OnOffApplication::m_local),
                           MakeAddressChecker())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&OnOffApplication::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute("OnTime",
                           "A RandomVariableStream used to pick the duration of the 'On' state.",
                           StringValue("ns3::ConstantRandomVariable[Constant=1.0]"),
@@ -186,6 +192,8 @@
         m_socket = Socket::CreateSocket(GetNode(), m_tid);
         int ret = -1;
 
+        NS_ABORT_MSG_IF(m_peer.IsInvalid(), "'Remote' attribute not properly set");
+
         if (!m_local.IsInvalid())
         {
             NS_ABORT_MSG_IF((Inet6SocketAddress::IsMatchingType(m_peer) &&
@@ -216,6 +224,10 @@
         m_socket->SetConnectCallback(MakeCallback(&OnOffApplication::ConnectionSucceeded, this),
                                      MakeCallback(&OnOffApplication::ConnectionFailed, this));
 
+        if (InetSocketAddress::IsMatchingType(m_peer))
+        {
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
+        }
         m_socket->Connect(m_peer);
         m_socket->SetAllowBroadcast(true);
         m_socket->ShutdownRecv();
@@ -256,7 +268,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_sendEvent.IsRunning() && m_cbrRateFailSafe == m_cbrRate)
+    if (m_sendEvent.IsPending() && m_cbrRateFailSafe == m_cbrRate)
     { // Cancel the pending send packet event
         // Calculate residual bits since last packet sent
         Time delta(Simulator::Now() - m_lastStartTime);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/onoff-application.h ns-3.42/src/applications/model/onoff-application.h
--- ns-3.41/src/applications/model/onoff-application.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/model/onoff-application.h	2024-05-29 15:29:46.920073000 -0700
@@ -122,22 +122,14 @@
      */
     Ptr<Socket> GetSocket() const;
 
-    /**
-     * \brief Assign a fixed random variable stream number to the random variables
-     * used by this model.
-     *
-     * \param stream first stream index to use
-     * \return the number of stream indices assigned by this model
-     */
-    int64_t AssignStreams(int64_t stream);
+    int64_t AssignStreams(int64_t stream) override;
 
   protected:
     void DoDispose() override;
 
   private:
-    // inherited from Application base class.
-    void StartApplication() override; // Called at time specified by Start
-    void StopApplication() override;  // Called at time specified by Stop
+    void StartApplication() override;
+    void StopApplication() override;
 
     // helpers
     /**
@@ -163,6 +155,7 @@
     Address m_peer;                      //!< Peer address
     Address m_local;                     //!< Local address to bind to
     bool m_connected;                    //!< True if connected
+    uint8_t m_tos;                       //!< The packets Type of Service
     Ptr<RandomVariableStream> m_onTime;  //!< rng for On Time
     Ptr<RandomVariableStream> m_offTime; //!< rng for Off Time
     DataRate m_cbrRate;                  //!< Rate that data is generated
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/packet-sink.cc ns-3.42/src/applications/model/packet-sink.cc
--- ns-3.41/src/applications/model/packet-sink.cc	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/model/packet-sink.cc	2024-05-29 15:29:46.920073000 -0700
@@ -133,6 +133,7 @@
     if (!m_socket)
     {
         m_socket = Socket::CreateSocket(GetNode(), m_tid);
+        NS_ABORT_MSG_IF(m_local.IsInvalid(), "'Local' attribute not properly set");
         if (m_socket->Bind(m_local) == -1)
         {
             NS_FATAL_ERROR("Failed to bind socket");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/packet-sink.h ns-3.42/src/applications/model/packet-sink.h
--- ns-3.41/src/applications/model/packet-sink.h	2024-02-09 14:44:07.853789800 -0800
+++ ns-3.42/src/applications/model/packet-sink.h	2024-05-29 15:29:46.920073000 -0700
@@ -115,9 +115,8 @@
     void DoDispose() override;
 
   private:
-    // inherited from Application base class.
-    void StartApplication() override; // Called at time specified by Start
-    void StopApplication() override;  // Called at time specified by Stop
+    void StartApplication() override;
+    void StopApplication() override;
 
     /**
      * \brief Handle a packet received by the application
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/three-gpp-http-client.cc ns-3.42/src/applications/model/three-gpp-http-client.cc
--- ns-3.41/src/applications/model/three-gpp-http-client.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/three-gpp-http-client.cc	2024-05-29 15:29:46.920073000 -0700
@@ -80,6 +80,12 @@
                           UintegerValue(80), // the default HTTP port
                           MakeUintegerAccessor(&ThreeGppHttpClient::m_remoteServerPort),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&ThreeGppHttpClient::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddTraceSource("RxPage",
                             "A page has been received.",
                             MakeTraceSourceAccessor(&ThreeGppHttpClient::m_rxPageTrace),
@@ -362,7 +368,8 @@
         m_state == PARSING_MAIN_OBJECT || m_state == READING)
     {
         m_socket = Socket::CreateSocket(GetNode(), TcpSocketFactory::GetTypeId());
-
+        NS_ABORT_MSG_IF(m_remoteServerAddress.IsInvalid(),
+                        "'RemoteServerAddress' attribute not properly set");
         if (Ipv4Address::IsMatchingType(m_remoteServerAddress))
         {
             int ret [[maybe_unused]];
@@ -375,6 +382,7 @@
             InetSocketAddress inetSocket = InetSocketAddress(ipv4, m_remoteServerPort);
             NS_LOG_INFO(this << " Connecting to " << ipv4 << " port " << m_remoteServerPort << " / "
                              << inetSocket << ".");
+            m_socket->SetIpTos(m_tos);
             ret = m_socket->Connect(inetSocket);
             NS_LOG_DEBUG(this << " Connect() return value= " << ret
                               << " GetErrNo= " << m_socket->GetErrno() << ".");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/three-gpp-http-client.h ns-3.42/src/applications/model/three-gpp-http-client.h
--- ns-3.41/src/applications/model/three-gpp-http-client.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/three-gpp-http-client.h	2024-05-29 15:29:46.920073000 -0700
@@ -188,14 +188,12 @@
                                          uint32_t numBytes);
 
   protected:
-    // Inherited from Object base class.
     void DoDispose() override;
 
-    // Inherited from Application base class.
+  private:
     void StartApplication() override;
     void StopApplication() override;
 
-  private:
     // SOCKET CALLBACK METHODS
 
     /**
@@ -393,6 +391,8 @@
     Address m_remoteServerAddress;
     /// The `RemoteServerPort` attribute.
     uint16_t m_remoteServerPort;
+    /// The `Tos` attribute.
+    uint8_t m_tos;
 
     // TRACE SOURCES
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/three-gpp-http-server.cc ns-3.42/src/applications/model/three-gpp-http-server.cc
--- ns-3.41/src/applications/model/three-gpp-http-server.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/three-gpp-http-server.cc	2024-05-29 15:29:46.920073000 -0700
@@ -81,6 +81,12 @@
                           UintegerValue(80), // the default HTTP port
                           MakeUintegerAccessor(&ThreeGppHttpServer::m_localPort),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&ThreeGppHttpServer::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute("Mtu",
                           "Maximum transmission unit (in bytes) of the TCP sockets "
                           "used in this application, excluding the compulsory 40 "
@@ -205,6 +211,9 @@
             m_initialSocket = Socket::CreateSocket(GetNode(), TcpSocketFactory::GetTypeId());
             m_initialSocket->SetAttribute("SegmentSize", UintegerValue(m_mtuSize));
 
+            NS_ABORT_MSG_IF(m_localAddress.IsInvalid(),
+                            "'LocalAddress' attribute not properly set");
+
             if (Ipv4Address::IsMatchingType(m_localAddress))
             {
                 const Ipv4Address ipv4 = Ipv4Address::ConvertFrom(m_localAddress);
@@ -214,6 +223,8 @@
                 int ret [[maybe_unused]] = m_initialSocket->Bind(inetSocket);
                 NS_LOG_DEBUG(this << " Bind() return value= " << ret
                                   << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
+
+                m_initialSocket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             }
             else if (Ipv6Address::IsMatchingType(m_localAddress))
             {
@@ -225,6 +236,10 @@
                 NS_LOG_DEBUG(this << " Bind() return value= " << ret
                                   << " GetErrNo= " << m_initialSocket->GetErrno() << ".");
             }
+            else
+            {
+                NS_ABORT_MSG("Incompatible local address");
+            }
 
             int ret [[maybe_unused]] = m_initialSocket->Listen();
             NS_LOG_DEBUG(this << " Listen () return value= " << ret
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/three-gpp-http-server.h ns-3.42/src/applications/model/three-gpp-http-server.h
--- ns-3.41/src/applications/model/three-gpp-http-server.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/three-gpp-http-server.h	2024-05-29 15:29:46.920073000 -0700
@@ -148,14 +148,12 @@
                                                   Ptr<Socket> socket);
 
   protected:
-    // Inherited from Object base class
     void DoDispose() override;
 
-    // Inherited from Application base class
+  private:
     void StartApplication() override;
     void StopApplication() override;
 
-  private:
     // SOCKET CALLBACK METHODS
 
     /**
@@ -272,6 +270,8 @@
     Address m_localAddress;
     /// The `LocalPort` attribute.
     uint16_t m_localPort;
+    /// The `Tos` attribute.
+    uint8_t m_tos;
     /// The `Mtu` attribute.
     uint32_t m_mtuSize;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-client.cc ns-3.42/src/applications/model/udp-client.cc
--- ns-3.41/src/applications/model/udp-client.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-client.cc	2024-05-29 15:29:46.920073000 -0700
@@ -71,6 +71,12 @@
                           UintegerValue(100),
                           MakeUintegerAccessor(&UdpClient::m_peerPort),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&UdpClient::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute("PacketSize",
                           "Size of packets generated. The minimum packet size is 12 bytes which is "
                           "the size of the header carrying the sequence number and the time stamp.",
@@ -118,13 +124,6 @@
 }
 
 void
-UdpClient::DoDispose()
-{
-    NS_LOG_FUNCTION(this);
-    Application::DoDispose();
-}
-
-void
 UdpClient::StartApplication()
 {
     NS_LOG_FUNCTION(this);
@@ -139,6 +138,7 @@
             {
                 NS_FATAL_ERROR("Failed to bind socket");
             }
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             m_socket->Connect(
                 InetSocketAddress(Ipv4Address::ConvertFrom(m_peerAddress), m_peerPort));
         }
@@ -157,6 +157,7 @@
             {
                 NS_FATAL_ERROR("Failed to bind socket");
             }
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             m_socket->Connect(m_peerAddress);
         }
         else if (Inet6SocketAddress::IsMatchingType(m_peerAddress))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-client.h ns-3.42/src/applications/model/udp-client.h
--- ns-3.41/src/applications/model/udp-client.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-client.h	2024-05-29 15:29:46.920073000 -0700
@@ -71,9 +71,6 @@
      */
     uint64_t GetTotalTx() const;
 
-  protected:
-    void DoDispose() override;
-
   private:
     void StartApplication() override;
     void StopApplication() override;
@@ -98,6 +95,7 @@
     Ptr<Socket> m_socket;  //!< Socket
     Address m_peerAddress; //!< Remote peer address
     uint16_t m_peerPort;   //!< Remote peer port
+    uint8_t m_tos;         //!< The packets Type of Service
     EventId m_sendEvent;   //!< Event to send the next packet
 
 #ifdef NS3_LOG_ENABLE
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-echo-client.cc ns-3.42/src/applications/model/udp-echo-client.cc
--- ns-3.41/src/applications/model/udp-echo-client.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-echo-client.cc	2024-05-29 15:29:46.920073000 -0700
@@ -65,6 +65,12 @@
                           UintegerValue(0),
                           MakeUintegerAccessor(&UdpEchoClient::m_peerPort),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&UdpEchoClient::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute(
                 "PacketSize",
                 "Size of echo data in outbound packets",
@@ -126,13 +132,6 @@
 }
 
 void
-UdpEchoClient::DoDispose()
-{
-    NS_LOG_FUNCTION(this);
-    Application::DoDispose();
-}
-
-void
 UdpEchoClient::StartApplication()
 {
     NS_LOG_FUNCTION(this);
@@ -141,12 +140,14 @@
     {
         TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
         m_socket = Socket::CreateSocket(GetNode(), tid);
+        NS_ABORT_MSG_IF(m_peerAddress.IsInvalid(), "'RemoteAddress' attribute not properly set");
         if (Ipv4Address::IsMatchingType(m_peerAddress))
         {
             if (m_socket->Bind() == -1)
             {
                 NS_FATAL_ERROR("Failed to bind socket");
             }
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             m_socket->Connect(
                 InetSocketAddress(Ipv4Address::ConvertFrom(m_peerAddress), m_peerPort));
         }
@@ -165,6 +166,7 @@
             {
                 NS_FATAL_ERROR("Failed to bind socket");
             }
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             m_socket->Connect(m_peerAddress);
         }
         else if (Inet6SocketAddress::IsMatchingType(m_peerAddress))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-echo-client.h ns-3.42/src/applications/model/udp-echo-client.h
--- ns-3.41/src/applications/model/udp-echo-client.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-echo-client.h	2024-05-29 15:29:46.920073000 -0700
@@ -130,9 +130,6 @@
      */
     void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
 
-  protected:
-    void DoDispose() override;
-
   private:
     void StartApplication() override;
     void StopApplication() override;
@@ -167,6 +164,7 @@
     Ptr<Socket> m_socket;  //!< Socket
     Address m_peerAddress; //!< Remote peer address
     uint16_t m_peerPort;   //!< Remote peer port
+    uint8_t m_tos;         //!< The packets Type of Service
     EventId m_sendEvent;   //!< Event to send the next packet
 
     /// Callbacks for tracing the packet Tx events
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-echo-server.cc ns-3.42/src/applications/model/udp-echo-server.cc
--- ns-3.41/src/applications/model/udp-echo-server.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-echo-server.cc	2024-05-29 15:29:46.920073000 -0700
@@ -51,6 +51,12 @@
                           UintegerValue(9),
                           MakeUintegerAccessor(&UdpEchoServer::m_port),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&UdpEchoServer::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddTraceSource("Rx",
                             "A packet has been received",
                             MakeTraceSourceAccessor(&UdpEchoServer::m_rxTrace),
@@ -75,13 +81,6 @@
 }
 
 void
-UdpEchoServer::DoDispose()
-{
-    NS_LOG_FUNCTION(this);
-    Application::DoDispose();
-}
-
-void
 UdpEchoServer::StartApplication()
 {
     NS_LOG_FUNCTION(this);
@@ -134,6 +133,7 @@
         }
     }
 
+    m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
     m_socket->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this));
     m_socket6->SetRecvCallback(MakeCallback(&UdpEchoServer::HandleRead, this));
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-echo-server.h ns-3.42/src/applications/model/udp-echo-server.h
--- ns-3.41/src/applications/model/udp-echo-server.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-echo-server.h	2024-05-29 15:29:46.920073000 -0700
@@ -52,9 +52,6 @@
     UdpEchoServer();
     ~UdpEchoServer() override;
 
-  protected:
-    void DoDispose() override;
-
   private:
     void StartApplication() override;
     void StopApplication() override;
@@ -69,6 +66,7 @@
     void HandleRead(Ptr<Socket> socket);
 
     uint16_t m_port;       //!< Port on which we listen for incoming packets.
+    uint8_t m_tos;         //!< The packets Type of Service
     Ptr<Socket> m_socket;  //!< IPv4 Socket
     Ptr<Socket> m_socket6; //!< IPv6 Socket
     Address m_local;       //!< local multicast address
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-server.cc ns-3.42/src/applications/model/udp-server.cc
--- ns-3.41/src/applications/model/udp-server.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-server.cc	2024-05-29 15:29:46.920073000 -0700
@@ -54,6 +54,12 @@
                           UintegerValue(100),
                           MakeUintegerAccessor(&UdpServer::m_port),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&UdpServer::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute("PacketWindowSize",
                           "The size of the window used to compute the packet loss. This value "
                           "should be a multiple of 8.",
@@ -73,10 +79,10 @@
 }
 
 UdpServer::UdpServer()
-    : m_lossCounter(0)
+    : m_received(0),
+      m_lossCounter(0)
 {
     NS_LOG_FUNCTION(this);
-    m_received = 0;
 }
 
 UdpServer::~UdpServer()
@@ -113,13 +119,6 @@
 }
 
 void
-UdpServer::DoDispose()
-{
-    NS_LOG_FUNCTION(this);
-    Application::DoDispose();
-}
-
-void
 UdpServer::StartApplication()
 {
     NS_LOG_FUNCTION(this);
@@ -135,6 +134,7 @@
         }
     }
 
+    m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
     m_socket->SetRecvCallback(MakeCallback(&UdpServer::HandleRead, this));
 
     if (!m_socket6)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-server.h ns-3.42/src/applications/model/udp-server.h
--- ns-3.41/src/applications/model/udp-server.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-server.h	2024-05-29 15:29:46.920073000 -0700
@@ -82,9 +82,6 @@
      */
     void SetPacketWindowSize(uint16_t size);
 
-  protected:
-    void DoDispose() override;
-
   private:
     void StartApplication() override;
     void StopApplication() override;
@@ -99,6 +96,7 @@
     void HandleRead(Ptr<Socket> socket);
 
     uint16_t m_port;                 //!< Port on which we listen for incoming packets.
+    uint8_t m_tos;                   //!< The packets Type of Service
     Ptr<Socket> m_socket;            //!< IPv4 Socket
     Ptr<Socket> m_socket6;           //!< IPv6 Socket
     uint64_t m_received;             //!< Number of received packets
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-trace-client.cc ns-3.42/src/applications/model/udp-trace-client.cc
--- ns-3.41/src/applications/model/udp-trace-client.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-trace-client.cc	2024-05-29 15:29:46.920073000 -0700
@@ -79,6 +79,12 @@
                           UintegerValue(100),
                           MakeUintegerAccessor(&UdpTraceClient::m_peerPort),
                           MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&UdpTraceClient::m_tos),
+                          MakeUintegerChecker<uint8_t>())
             .AddAttribute("MaxPacketSize",
                           "The maximum size of a packet (including the SeqTsHeader, 12 bytes).",
                           UintegerValue(1024),
@@ -176,13 +182,6 @@
 }
 
 void
-UdpTraceClient::DoDispose()
-{
-    NS_LOG_FUNCTION(this);
-    Application::DoDispose();
-}
-
-void
 UdpTraceClient::LoadTrace(std::string filename)
 {
     NS_LOG_FUNCTION(this << filename);
@@ -258,12 +257,14 @@
     {
         TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
         m_socket = Socket::CreateSocket(GetNode(), tid);
+        NS_ABORT_MSG_IF(m_peerAddress.IsInvalid(), "'RemoteAddress' attribute not properly set");
         if (Ipv4Address::IsMatchingType(m_peerAddress))
         {
             if (m_socket->Bind() == -1)
             {
                 NS_FATAL_ERROR("Failed to bind socket");
             }
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             m_socket->Connect(
                 InetSocketAddress(Ipv4Address::ConvertFrom(m_peerAddress), m_peerPort));
         }
@@ -282,6 +283,7 @@
             {
                 NS_FATAL_ERROR("Failed to bind socket");
             }
+            m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
             m_socket->Connect(m_peerAddress);
         }
         else if (Inet6SocketAddress::IsMatchingType(m_peerAddress))
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/model/udp-trace-client.h ns-3.42/src/applications/model/udp-trace-client.h
--- ns-3.41/src/applications/model/udp-trace-client.h	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/model/udp-trace-client.h	2024-05-29 15:29:46.920073000 -0700
@@ -124,10 +124,10 @@
      */
     void SetTraceLoop(bool traceLoop);
 
-  protected:
-    void DoDispose() override;
-
   private:
+    void StartApplication() override;
+    void StopApplication() override;
+
     /**
      * \brief Load a trace file
      * \param filename the trace file path
@@ -137,8 +137,6 @@
      * \brief Load the default trace
      */
     void LoadDefaultTrace();
-    void StartApplication() override;
-    void StopApplication() override;
 
     /**
      * \brief Send a packet
@@ -166,6 +164,7 @@
     Ptr<Socket> m_socket;  //!< Socket
     Address m_peerAddress; //!< Remote peer address
     uint16_t m_peerPort;   //!< Remote peer port
+    uint8_t m_tos;         //!< The packets Type of Service
     EventId m_sendEvent;   //!< Event to send the next packet
 
     std::vector<TraceEntry> m_entries;    //!< Entries in the trace to send
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/test/bulk-send-application-test-suite.cc ns-3.42/src/applications/test/bulk-send-application-test-suite.cc
--- ns-3.41/src/applications/test/bulk-send-application-test-suite.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/test/bulk-send-application-test-suite.cc	2024-05-29 15:29:46.920073000 -0700
@@ -274,10 +274,10 @@
 };
 
 BulkSendTestSuite::BulkSendTestSuite()
-    : TestSuite("bulk-send-application", UNIT)
+    : TestSuite("applications-bulk-send", Type::UNIT)
 {
-    AddTestCase(new BulkSendBasicTestCase, TestCase::QUICK);
-    AddTestCase(new BulkSendSeqTsSizeTestCase, TestCase::QUICK);
+    AddTestCase(new BulkSendBasicTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new BulkSendSeqTsSizeTestCase, TestCase::Duration::QUICK);
 }
 
 static BulkSendTestSuite g_bulkSendTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/test/three-gpp-http-client-server-test.cc ns-3.42/src/applications/test/three-gpp-http-client-server-test.cc
--- ns-3.41/src/applications/test/three-gpp-http-client-server-test.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/test/three-gpp-http-client-server-test.cc	2024-05-29 15:29:46.920073000 -0700
@@ -799,7 +799,7 @@
   public:
     /// Instantiate the test suite.
     ThreeGppHttpClientServerTestSuite()
-        : TestSuite("three-gpp-http-client-server-test", SYSTEM)
+        : TestSuite("applications-three-gpp-http-client-server", Type::SYSTEM)
     {
         // LogComponentEnable ("ThreeGppHttpClientServerTest", LOG_INFO);
         // LogComponentEnable ("ThreeGppHttpClient", LOG_INFO);
@@ -873,14 +873,14 @@
         }
 
         // Assign higher fullness for tests with higher RngRun.
-        TestCase::TestDuration testDuration = TestCase::QUICK;
+        TestCase::Duration testDuration = TestCase::Duration::QUICK;
         if (rngRun > 20)
         {
-            testDuration = TestCase::EXTENSIVE;
+            testDuration = TestCase::Duration::EXTENSIVE;
         }
         if (rngRun > 50)
         {
-            testDuration = TestCase::TAKES_FOREVER;
+            testDuration = TestCase::Duration::TAKES_FOREVER;
         }
 
         AddTestCase(new ThreeGppHttpObjectTestCase(name.str(),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/applications/test/udp-client-server-test.cc ns-3.42/src/applications/test/udp-client-server-test.cc
--- ns-3.41/src/applications/test/udp-client-server-test.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/applications/test/udp-client-server-test.cc	2024-05-29 15:29:46.920073000 -0700
@@ -97,29 +97,28 @@
     Ipv4InterfaceContainer i = ipv4.Assign(d);
 
     uint16_t port = 4000;
-    UdpServerHelper server(port);
-    ApplicationContainer apps = server.Install(n.Get(1));
-    apps.Start(Seconds(1.0));
-    apps.Stop(Seconds(10.0));
+    UdpServerHelper serverHelper(port);
+    auto serverApp = serverHelper.Install(n.Get(1));
+    serverApp.Start(Seconds(1.0));
+    serverApp.Stop(Seconds(10.0));
 
     uint32_t MaxPacketSize = 1024;
     Time interPacketInterval = Seconds(1.);
     uint32_t maxPacketCount = 10;
-    UdpClientHelper client(i.GetAddress(1), port);
-    client.SetAttribute("MaxPackets", UintegerValue(maxPacketCount));
-    client.SetAttribute("Interval", TimeValue(interPacketInterval));
-    client.SetAttribute("PacketSize", UintegerValue(MaxPacketSize));
-    apps = client.Install(n.Get(0));
-    apps.Start(Seconds(2.0));
-    apps.Stop(Seconds(10.0));
+    UdpClientHelper clientHelper(i.GetAddress(1), port);
+    clientHelper.SetAttribute("MaxPackets", UintegerValue(maxPacketCount));
+    clientHelper.SetAttribute("Interval", TimeValue(interPacketInterval));
+    clientHelper.SetAttribute("PacketSize", UintegerValue(MaxPacketSize));
+    auto clientApp = clientHelper.Install(n.Get(0));
+    clientApp.Start(Seconds(2.0));
+    clientApp.Stop(Seconds(10.0));
 
     Simulator::Run();
     Simulator::Destroy();
 
-    NS_TEST_ASSERT_MSG_EQ(server.GetServer()->GetLost(), 0, "Packets were lost !");
-    NS_TEST_ASSERT_MSG_EQ(server.GetServer()->GetReceived(),
-                          8,
-                          "Did not receive expected number of packets !");
+    auto server = DynamicCast<UdpServer>(serverApp.Get(0));
+    NS_TEST_ASSERT_MSG_EQ(server->GetLost(), 0, "Packets were lost !");
+    NS_TEST_ASSERT_MSG_EQ(server->GetReceived(), 8, "Did not receive expected number of packets !");
 }
 
 /**
@@ -173,23 +172,24 @@
     Ipv4InterfaceContainer i = ipv4.Assign(d);
 
     uint16_t port = 4000;
-    UdpServerHelper server(port);
-    ApplicationContainer apps = server.Install(n.Get(1));
-    apps.Start(Seconds(1.0));
-    apps.Stop(Seconds(10.0));
+    UdpServerHelper serverHelper(port);
+    auto serverApp = serverHelper.Install(n.Get(1));
+    serverApp.Start(Seconds(1.0));
+    serverApp.Stop(Seconds(10.0));
 
     uint32_t MaxPacketSize = 1400 - 28; // ip/udp header
-    UdpTraceClientHelper client(i.GetAddress(1), port, "");
-    client.SetAttribute("MaxPacketSize", UintegerValue(MaxPacketSize));
-    apps = client.Install(n.Get(0));
-    apps.Start(Seconds(2.0));
-    apps.Stop(Seconds(10.0));
+    UdpTraceClientHelper clientHelper(i.GetAddress(1), port);
+    clientHelper.SetAttribute("MaxPacketSize", UintegerValue(MaxPacketSize));
+    auto clientApp = clientHelper.Install(n.Get(0));
+    clientApp.Start(Seconds(2.0));
+    clientApp.Stop(Seconds(10.0));
 
     Simulator::Run();
     Simulator::Destroy();
 
-    NS_TEST_ASSERT_MSG_EQ(server.GetServer()->GetLost(), 0, "Packets were lost !");
-    NS_TEST_ASSERT_MSG_EQ(server.GetServer()->GetReceived(),
+    auto server = DynamicCast<UdpServer>(serverApp.Get(0));
+    NS_TEST_ASSERT_MSG_EQ(server->GetLost(), 0, "Packets were lost !");
+    NS_TEST_ASSERT_MSG_EQ(server->GetReceived(),
                           247,
                           "Did not receive expected number of packets !");
 }
@@ -359,12 +359,12 @@
 };
 
 UdpClientServerTestSuite::UdpClientServerTestSuite()
-    : TestSuite("udp-client-server", UNIT)
+    : TestSuite("applications-udp-client-server", Type::UNIT)
 {
-    AddTestCase(new UdpTraceClientServerTestCase, TestCase::QUICK);
-    AddTestCase(new UdpClientServerTestCase, TestCase::QUICK);
-    AddTestCase(new PacketLossCounterTestCase, TestCase::QUICK);
-    AddTestCase(new UdpEchoClientSetFillTestCase, TestCase::QUICK);
+    AddTestCase(new UdpTraceClientServerTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new UdpClientServerTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new PacketLossCounterTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new UdpEchoClientSetFillTestCase, TestCase::Duration::QUICK);
 }
 
 static UdpClientServerTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/bridge/examples/csma-bridge.py ns-3.42/src/bridge/examples/csma-bridge.py
--- ns-3.41/src/bridge/examples/csma-bridge.py	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/bridge/examples/csma-bridge.py	2024-05-29 15:29:46.920073000 -0700
@@ -48,53 +48,51 @@
     # Allow the user to override any of the defaults and the above Bind() at
     # run-time, via command-line arguments
     #
-    cmd = ns.core.CommandLine()
+    cmd = ns.CommandLine()
     cmd.Parse(argv)
 
     #
     # Explicitly create the nodes required by the topology(shown above).
     #
     # print "Create nodes."
-    terminals = ns.network.NodeContainer()
+    terminals = ns.NodeContainer()
     terminals.Create(4)
 
-    csmaSwitch = ns.network.NodeContainer()
+    csmaSwitch = ns.NodeContainer()
     csmaSwitch.Create(1)
 
     # print "Build Topology"
-    csma = ns.csma.CsmaHelper()
-    csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000)))
-    csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2)))
+    csma = ns.CsmaHelper()
+    csma.SetChannelAttribute("DataRate", ns.DataRateValue(ns.DataRate(5000000)))
+    csma.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(2)))
 
     # Create the csma links, from each terminal to the switch
 
-    terminalDevices = ns.network.NetDeviceContainer()
-    switchDevices = ns.network.NetDeviceContainer()
+    terminalDevices = ns.NetDeviceContainer()
+    switchDevices = ns.NetDeviceContainer()
 
     for i in range(4):
-        link = csma.Install(
-            ns.network.NodeContainer(ns.network.NodeContainer(terminals.Get(i)), csmaSwitch)
-        )
+        link = csma.Install(ns.NodeContainer(ns.NodeContainer(terminals.Get(i)), csmaSwitch))
         terminalDevices.Add(link.Get(0))
         switchDevices.Add(link.Get(1))
 
     # Create the bridge netdevice, which will do the packet switching
     switchNode = csmaSwitch.Get(0)
-    bridgeDevice = ns.bridge.BridgeNetDevice()
+    bridgeDevice = ns.BridgeNetDevice()
     switchNode.AddDevice(bridgeDevice)
 
     for portIter in range(switchDevices.GetN()):
         bridgeDevice.AddBridgePort(switchDevices.Get(portIter))
 
     # Add internet stack to the terminals
-    internet = ns.internet.InternetStackHelper()
+    internet = ns.InternetStackHelper()
     internet.Install(terminals)
 
     # We've got the "hardware" in place.  Now we need to add IP addresses.
     #
     # print "Assign IP Addresses."
-    ipv4 = ns.internet.Ipv4AddressHelper()
-    ipv4.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
+    ipv4 = ns.Ipv4AddressHelper()
+    ipv4.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
     ipv4.Assign(terminalDevices)
 
     #
@@ -103,39 +101,39 @@
     # print "Create Applications."
     port = 9  # Discard port(RFC 863)
 
-    inet_sock_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.2"), port)
-    onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", inet_sock_address.ConvertTo())
-    onoff.SetConstantRate(ns.network.DataRate("500kb/s"))
+    inet_sock_address = ns.InetSocketAddress(ns.Ipv4Address("10.1.1.2"), port)
+    onoff = ns.OnOffHelper("ns3::UdpSocketFactory", inet_sock_address.ConvertTo())
+    onoff.SetConstantRate(ns.DataRate("500kb/s"))
 
-    app = onoff.Install(ns.network.NodeContainer(terminals.Get(0)))
+    app = onoff.Install(ns.NodeContainer(terminals.Get(0)))
     # Start the application
-    app.Start(ns.core.Seconds(1.0))
-    app.Stop(ns.core.Seconds(10.0))
+    app.Start(ns.Seconds(1.0))
+    app.Stop(ns.Seconds(10.0))
 
     # Create an optional packet sink to receive these packets
-    inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)
-    sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory", inet_address.ConvertTo())
-    app = sink.Install(ns.network.NodeContainer(terminals.Get(1)))
-    app.Start(ns.core.Seconds(0.0))
+    inet_address = ns.InetSocketAddress(ns.Ipv4Address.GetAny(), port)
+    sink = ns.PacketSinkHelper("ns3::UdpSocketFactory", inet_address.ConvertTo())
+    app = sink.Install(ns.NodeContainer(terminals.Get(1)))
+    app.Start(ns.Seconds(0.0))
 
     #
     # Create a similar flow from n3 to n0, starting at time 1.1 seconds
     #
-    inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.1"), port)
-    onoff.SetAttribute("Remote", ns.network.AddressValue(inet_address.ConvertTo()))
-    app = onoff.Install(ns.network.NodeContainer(terminals.Get(3)))
-    app.Start(ns.core.Seconds(1.1))
-    app.Stop(ns.core.Seconds(10.0))
+    inet_address = ns.InetSocketAddress(ns.Ipv4Address("10.1.1.1"), port)
+    onoff.SetAttribute("Remote", ns.AddressValue(inet_address.ConvertTo()))
+    app = onoff.Install(ns.NodeContainer(terminals.Get(3)))
+    app.Start(ns.Seconds(1.1))
+    app.Stop(ns.Seconds(10.0))
 
-    app = sink.Install(ns.network.NodeContainer(terminals.Get(0)))
-    app.Start(ns.core.Seconds(0.0))
+    app = sink.Install(ns.NodeContainer(terminals.Get(0)))
+    app.Start(ns.Seconds(0.0))
 
     #
     # Configure tracing of all enqueue, dequeue, and NetDevice receive events.
     # Trace output will be sent to the file "csma-bridge.tr"
     #
     # print "Configure Tracing."
-    # ascii = ns.network.AsciiTraceHelper();
+    # ascii = ns.AsciiTraceHelper();
     # csma.EnableAsciiAll(ascii.CreateFileStream ("csma-bridge.tr"));
 
     #
@@ -151,8 +149,8 @@
     # Now, do the actual simulation.
     #
     # print "Run Simulation."
-    ns.core.Simulator.Run()
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Run()
+    ns.Simulator.Destroy()
     # print "Done."
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/bridge/model/bridge-net-device.cc ns-3.42/src/bridge/model/bridge-net-device.cc
--- ns-3.41/src/bridge/model/bridge-net-device.cc	2024-02-09 14:44:07.857789800 -0800
+++ ns-3.42/src/bridge/model/bridge-net-device.cc	2024-05-29 15:29:46.920073000 -0700
@@ -355,7 +355,7 @@
 BridgeNetDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION_NOARGS();
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/brite/test/brite-test-topology.cc ns-3.42/src/brite/test/brite-test-topology.cc
--- ns-3.41/src/brite/test/brite-test-topology.cc	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/brite/test/brite-test-topology.cc	2024-05-29 15:29:46.924073000 -0700
@@ -215,10 +215,10 @@
 {
   public:
     BriteTestSuite()
-        : TestSuite("brite-testing", UNIT)
+        : TestSuite("brite-testing", Type::UNIT)
     {
-        AddTestCase(new BriteTopologyStructureTestCase, TestCase::QUICK);
-        AddTestCase(new BriteTopologyFunctionTestCase, TestCase::QUICK);
+        AddTestCase(new BriteTopologyStructureTestCase, TestCase::Duration::QUICK);
+        AddTestCase(new BriteTopologyFunctionTestCase, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/doc/Makefile ns-3.42/src/buildings/doc/Makefile
--- ns-3.41/src/buildings/doc/Makefile	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/doc/Makefile	2024-05-29 15:29:46.924073000 -0700
@@ -40,7 +40,7 @@
 	@if test x$($@_width) != x; then $(RESCALE) $($@_width) $@ ; fi
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/helper/building-container.h ns-3.42/src/buildings/helper/building-container.h
--- ns-3.41/src/buildings/helper/building-container.h	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/helper/building-container.h	2024-05-29 15:29:46.924073000 -0700
@@ -30,6 +30,8 @@
 {
 
 /**
+ * \ingroup buildings
+ *
  * \brief keep track of a set of building pointers.
  *
  * Some ns-3 helpers operate on more than one building at a time.  For example
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/helper/building-position-allocator.h ns-3.42/src/buildings/helper/building-position-allocator.h
--- ns-3.41/src/buildings/helper/building-position-allocator.h	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/helper/building-position-allocator.h	2024-05-29 15:29:46.924073000 -0700
@@ -32,6 +32,8 @@
 class UniformRandomVariable;
 
 /**
+ * \ingroup buildings
+ *
  * Allocate each position by randomly choosing a building from the list
  * of all buildings, and then randomly choosing a position inside the building.
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/helper/buildings-helper.h ns-3.42/src/buildings/helper/buildings-helper.h
--- ns-3.41/src/buildings/helper/buildings-helper.h	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/helper/buildings-helper.h	2024-05-29 15:29:46.924073000 -0700
@@ -34,6 +34,8 @@
 class Building;
 
 /**
+ * \ingroup buildings
+ *
  * Helper used to install a MobilityBuildingInfo into a set of nodes.
  */
 class BuildingsHelper
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/building.h ns-3.42/src/buildings/model/building.h
--- ns-3.41/src/buildings/model/building.h	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/model/building.h	2024-05-29 15:29:46.924073000 -0700
@@ -31,7 +31,13 @@
 {
 
 /**
- * \ingroup mobility
+ * \defgroup buildings Buildings
+ *
+ * The models to define 3d buildings, associated channel models, and mobility.
+ */
+
+/**
+ * \ingroup buildings
  * \brief a 3d building block
  */
 class Building : public Object
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/building-list.h ns-3.42/src/buildings/model/building-list.h
--- ns-3.41/src/buildings/model/building-list.h	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/model/building-list.h	2024-05-29 15:29:46.924073000 -0700
@@ -32,6 +32,8 @@
 class Building;
 
 /**
+ * \ingroup buildings
+ *
  * Container for Building class
  */
 class BuildingList
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/buildings-channel-condition-model.h ns-3.42/src/buildings/model/buildings-channel-condition-model.h
--- ns-3.41/src/buildings/model/buildings-channel-condition-model.h	2024-02-09 14:44:07.861789700 -0800
+++ ns-3.42/src/buildings/model/buildings-channel-condition-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -30,6 +30,7 @@
 
 /**
  * \ingroup buildings
+ * \ingroup propagation
  *
  * \brief Determines the channel condition based on the buildings deployed in the
  * scenario
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/buildings-propagation-loss-model.h ns-3.42/src/buildings/model/buildings-propagation-loss-model.h
--- ns-3.41/src/buildings/model/buildings-propagation-loss-model.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/buildings-propagation-loss-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -36,6 +36,7 @@
 class JakesFadingLossModel;
 
 /**
+ * \ingroup buildings
  * \ingroup propagation
  *
  *  This model provides means for simulating the following propagation
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/hybrid-buildings-propagation-loss-model.h ns-3.42/src/buildings/model/hybrid-buildings-propagation-loss-model.h
--- ns-3.41/src/buildings/model/hybrid-buildings-propagation-loss-model.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/hybrid-buildings-propagation-loss-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -36,6 +36,7 @@
 class Kun2600MhzPropagationLossModel;
 
 /**
+ * \ingroup buildings
  * \ingroup propagation
  *
  *  \brief The HybridBuildingsPropagationModel is a compound of different models able to evaluate
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/itu-r-1238-propagation-loss-model.h ns-3.42/src/buildings/model/itu-r-1238-propagation-loss-model.h
--- ns-3.41/src/buildings/model/itu-r-1238-propagation-loss-model.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/itu-r-1238-propagation-loss-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -29,6 +29,9 @@
 {
 
 /**
+ * \ingroup buildings
+ * \ingroup propagation
+ *
  * This class implements the ITU-R 1238 propagation loss model.
  *
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/mobility-building-info.h ns-3.42/src/buildings/model/mobility-building-info.h
--- ns-3.41/src/buildings/model/mobility-building-info.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/mobility-building-info.h	2024-05-29 15:29:46.924073000 -0700
@@ -36,6 +36,8 @@
 
 /**
  * \ingroup buildings
+ * \ingroup mobility
+
  * \brief mobility buildings information (to be used by mobility models)
  *
  * This model implements the management of scenarios where users might be
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/oh-buildings-propagation-loss-model.h ns-3.42/src/buildings/model/oh-buildings-propagation-loss-model.h
--- ns-3.41/src/buildings/model/oh-buildings-propagation-loss-model.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/oh-buildings-propagation-loss-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -29,6 +29,7 @@
 class OkumuraHataPropagationLossModel;
 
 /**
+ * \ingroup buildings
  * \ingroup propagation
  *
  *  this model combines the OkumuraHata model with the BuildingsPropagationLossModel
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc ns-3.42/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc
--- ns-3.41/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/random-walk-2d-outdoor-mobility-model.cc	2024-05-29 15:29:46.924073000 -0700
@@ -115,8 +115,8 @@
     m_helper.Update();
     double speed = m_speed->GetValue();
     double direction = m_direction->GetValue();
-    Vector vector(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
-    m_helper.SetVelocity(vector);
+    Vector velocity(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
+    m_helper.SetVelocity(velocity);
     m_helper.Unpause();
 
     Time delayLeft;
@@ -142,10 +142,10 @@
     NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
 
     Vector position = m_helper.GetCurrentPosition();
-    Vector speed = m_helper.GetVelocity();
+    Vector velocity = m_helper.GetVelocity();
     Vector nextPosition = position;
-    nextPosition.x += speed.x * delayLeft.GetSeconds();
-    nextPosition.y += speed.y * delayLeft.GetSeconds();
+    nextPosition.x += velocity.x * delayLeft.GetSeconds();
+    nextPosition.y += velocity.y * delayLeft.GetSeconds();
     m_event.Cancel();
 
     // check if the nextPosition is inside a building, or if the line
@@ -170,13 +170,13 @@
 
             double delaySecondsX = std::numeric_limits<double>::max();
             double delaySecondsY = std::numeric_limits<double>::max();
-            if (speed.x != 0)
+            if (velocity.x != 0)
             {
-                delaySecondsX = std::abs((nextPosition.x - position.x) / speed.x);
+                delaySecondsX = std::abs((nextPosition.x - position.x) / velocity.x);
             }
-            if (speed.y != 0)
+            if (velocity.y != 0)
             {
-                delaySecondsY = std::abs((nextPosition.y - position.y) / speed.y);
+                delaySecondsY = std::abs((nextPosition.y - position.y) / velocity.y);
             }
             Time delay = Seconds(std::min(delaySecondsX, delaySecondsY));
             m_event = Simulator::Schedule(delay,
@@ -189,7 +189,7 @@
     else
     {
         NS_LOG_LOGIC("Out of bounding box");
-        nextPosition = m_bounds.CalculateIntersection(position, speed);
+        nextPosition = m_bounds.CalculateIntersection(position, velocity);
         // check that this nextPosition is outdoor
         auto outdoorBuilding = IsLineClearOfBuildings(position, nextPosition);
         bool outdoor = std::get<0>(outdoorBuilding);
@@ -198,15 +198,15 @@
         if (outdoor)
         {
             double delaySeconds = std::numeric_limits<double>::max();
-            if (speed.x != 0)
+            if (velocity.x != 0)
             {
                 delaySeconds =
-                    std::min(delaySeconds, std::abs((nextPosition.x - position.x) / speed.x));
+                    std::min(delaySeconds, std::abs((nextPosition.x - position.x) / velocity.x));
             }
-            else if (speed.y != 0)
+            else if (velocity.y != 0)
             {
                 delaySeconds =
-                    std::min(delaySeconds, std::abs((nextPosition.y - position.y) / speed.y));
+                    std::min(delaySeconds, std::abs((nextPosition.y - position.y) / velocity.y));
             }
             else
             {
@@ -228,15 +228,15 @@
 
             double delaySecondsX = std::numeric_limits<double>::max();
             double delaySecondsY = std::numeric_limits<double>::max();
-            if (speed.x != 0)
+            if (velocity.x != 0)
             {
                 delaySecondsX =
-                    std::min(delaySecondsX, std::abs((nextPosition.x - position.x) / speed.x));
+                    std::min(delaySecondsX, std::abs((nextPosition.x - position.x) / velocity.x));
             }
-            if (speed.y != 0)
+            if (velocity.y != 0)
             {
                 delaySecondsY =
-                    std::min(delaySecondsY, std::abs((nextPosition.y - position.y) / speed.y));
+                    std::min(delaySecondsY, std::abs((nextPosition.y - position.y) / velocity.y));
             }
             if (delaySecondsX == std::numeric_limits<double>::max() &&
                 delaySecondsY == std::numeric_limits<double>::max())
@@ -381,30 +381,29 @@
     NS_LOG_FUNCTION(this << delayLeft.GetSeconds());
     m_helper.UpdateWithBounds(m_bounds);
     Vector position = m_helper.GetCurrentPosition();
-    Vector speed = m_helper.GetVelocity();
+    Vector velocity = m_helper.GetVelocity();
     switch (m_bounds.GetClosestSideOrCorner(position))
     {
     case Rectangle::RIGHTSIDE:
     case Rectangle::LEFTSIDE:
         NS_LOG_DEBUG("The closest side is RIGHT or LEFT");
-        speed.x = -speed.x;
+        velocity.x = -velocity.x;
         break;
     case Rectangle::TOPSIDE:
     case Rectangle::BOTTOMSIDE:
         NS_LOG_DEBUG("The closest side is TOP or BOTTOM");
-        speed.y = -speed.y;
+        velocity.y = -velocity.y;
         break;
     case Rectangle::TOPRIGHTCORNER:
     case Rectangle::BOTTOMRIGHTCORNER:
     case Rectangle::TOPLEFTCORNER:
     case Rectangle::BOTTOMLEFTCORNER:
         NS_LOG_DEBUG("The closest side is a corner");
-        auto temp = speed.x;
-        speed.x = -speed.y;
-        speed.y = -temp;
+        velocity.x = -velocity.x;
+        velocity.y = -velocity.y;
         break;
     }
-    m_helper.SetVelocity(speed);
+    m_helper.SetVelocity(velocity);
     m_helper.Unpause();
     DoWalk(delayLeft);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/random-walk-2d-outdoor-mobility-model.h ns-3.42/src/buildings/model/random-walk-2d-outdoor-mobility-model.h
--- ns-3.41/src/buildings/model/random-walk-2d-outdoor-mobility-model.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/random-walk-2d-outdoor-mobility-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -36,7 +36,9 @@
 {
 
 /**
+ * \ingroup buildings
  * \ingroup mobility
+ *
  * \brief 2D random walk mobility model which avoids buildings.
  *
  * This class reuses most of the code of RandomWalk2dMobilityModel,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/model/three-gpp-v2v-channel-condition-model.h ns-3.42/src/buildings/model/three-gpp-v2v-channel-condition-model.h
--- ns-3.41/src/buildings/model/three-gpp-v2v-channel-condition-model.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/model/three-gpp-v2v-channel-condition-model.h	2024-05-29 15:29:46.924073000 -0700
@@ -33,6 +33,7 @@
 
 /**
  * \ingroup buildings
+ * \ingroup propagation
  *
  * \brief Computes the channel condition for the V2V Urban scenario
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/building-position-allocator-test.cc ns-3.42/src/buildings/test/building-position-allocator-test.cc
--- ns-3.41/src/buildings/test/building-position-allocator-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/building-position-allocator-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -35,13 +35,13 @@
 NS_LOG_COMPONENT_DEFINE("BuildingPositionAllocatorTest");
 
 /**
- * \ingroup propagation
+ * \ingroup buildings
+ * \ingroup tests
  * \defgroup building-test Buildings module tests
  */
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Room coordinates
  */
@@ -75,7 +75,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * RandomRoomPositionAllocator test
  */
@@ -153,7 +152,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * SameRoomPositionAllocator test
  */
@@ -227,7 +225,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * \brief RandomRoomPositionAllocator TestSuite
  */
@@ -238,12 +235,12 @@
 };
 
 BuildingPositionAllocatorTestSuite::BuildingPositionAllocatorTestSuite()
-    : TestSuite("building-position-allocator", UNIT)
+    : TestSuite("building-position-allocator", Type::UNIT)
 {
     NS_LOG_FUNCTION(this);
 
-    AddTestCase(new RandomRoomPositionAllocatorTestCase, TestCase::QUICK);
-    AddTestCase(new SameRoomPositionAllocatorTestCase, TestCase::QUICK);
+    AddTestCase(new RandomRoomPositionAllocatorTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new SameRoomPositionAllocatorTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-channel-condition-model-test.cc ns-3.42/src/buildings/test/buildings-channel-condition-model-test.cc
--- ns-3.41/src/buildings/test/buildings-channel-condition-model-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-channel-condition-model-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -31,7 +31,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test case for the class BuildingsChannelConditionModel. It checks if the
  * channel condition is correctly determined when a building is deployed in the
@@ -148,7 +147,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  * Test suite for the buildings channel condition model
  */
 class BuildingsChannelConditionModelsTestSuite : public TestSuite
@@ -158,9 +156,9 @@
 };
 
 BuildingsChannelConditionModelsTestSuite::BuildingsChannelConditionModelsTestSuite()
-    : TestSuite("buildings-channel-condition-model", UNIT)
+    : TestSuite("buildings-channel-condition-model", Type::UNIT)
 {
-    AddTestCase(new BuildingsChannelConditionModelTestCase, TestCase::QUICK);
+    AddTestCase(new BuildingsChannelConditionModelTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-helper-test.cc ns-3.42/src/buildings/test/buildings-helper-test.cc
--- ns-3.41/src/buildings/test/buildings-helper-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-helper-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -32,7 +32,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * \brief Struct representing a position in a building
  */
@@ -59,7 +58,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
 
  * Data to construct a Building object. We don't want to pass Building
  * objects to the TestCase constructor because otherwise BuildingList
@@ -96,7 +94,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * \brief BuildingsHelper test
  */
@@ -197,7 +194,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * \brief BuildingsHelper TestSuite
  */
@@ -208,7 +204,7 @@
 };
 
 BuildingsHelperTestSuite::BuildingsHelperTestSuite()
-    : TestSuite("buildings-helper", UNIT)
+    : TestSuite("buildings-helper", Type::UNIT)
 {
     NS_LOG_FUNCTION(this);
 
@@ -231,25 +227,25 @@
     p1.rx = 1;
     p1.ry = 1;
     p1.fn = 1;
-    AddTestCase(new BuildingsHelperOneTestCase(p1, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p1, b1), TestCase::Duration::QUICK);
 
     Vector vp2(1.5, 0.5, 0.5);
     PositionInBuilding p2;
     p2.pos = vp2;
     p2.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p2, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p2, b1), TestCase::Duration::QUICK);
 
     Vector vp3(1.5, 2.5, 0.5);
     PositionInBuilding p3;
     p3.pos = vp3;
     p3.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p3, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p3, b1), TestCase::Duration::QUICK);
 
     Vector vp4(1.5, 1.5, 5);
     PositionInBuilding p4;
     p4.pos = vp4;
     p4.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p4, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p4, b1), TestCase::Duration::QUICK);
 
     Vector vp5(2.5, 1.6, 3.5);
     PositionInBuilding p5;
@@ -259,31 +255,31 @@
     p5.rx = 1;
     p5.ry = 1;
     p5.fn = 1;
-    AddTestCase(new BuildingsHelperOneTestCase(p5, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p5, b1), TestCase::Duration::QUICK);
 
     Vector vp6(0.9999, 1.5, 1.5);
     PositionInBuilding p6;
     p6.pos = vp6;
     p6.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p6, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p6, b1), TestCase::Duration::QUICK);
 
     Vector vp7(3.0001, 1.5, 2.5);
     PositionInBuilding p7;
     p7.pos = vp7;
     p7.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p7, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p7, b1), TestCase::Duration::QUICK);
 
     Vector vp8(1.001, 1.001, -0.01);
     PositionInBuilding p8;
     p8.pos = vp8;
     p8.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p8, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p8, b1), TestCase::Duration::QUICK);
 
     Vector vp9(1.5, 1.5, 4.001);
     PositionInBuilding p9;
     p9.pos = vp9;
     p9.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(p9, b1), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(p9, b1), TestCase::Duration::QUICK);
 
     BuildingData b2;
     b2.xmin = -1;
@@ -304,7 +300,7 @@
     q1.rx = 1;
     q1.ry = 2;
     q1.fn = 3;
-    AddTestCase(new BuildingsHelperOneTestCase(q1, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q1, b2), TestCase::Duration::QUICK);
 
     Vector vq2(0.2, 0.3, 0.2);
     PositionInBuilding q2;
@@ -314,37 +310,37 @@
     q2.rx = 3;
     q2.ry = 5;
     q2.fn = 1;
-    AddTestCase(new BuildingsHelperOneTestCase(q2, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q2, b2), TestCase::Duration::QUICK);
 
     Vector vq3(0.6, -1.75, 1.5);
     PositionInBuilding q3;
     q3.pos = vq3;
     q3.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(q3, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q3, b2), TestCase::Duration::QUICK);
 
     Vector vq4(-1.01, 0.3, 1.99);
     PositionInBuilding q4;
     q4.pos = vq4;
     q4.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(q4, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q4, b2), TestCase::Duration::QUICK);
 
     Vector vq5(-0.8, 0.7, 0.01);
     PositionInBuilding q5;
     q5.pos = vq5;
     q5.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(q5, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q5, b2), TestCase::Duration::QUICK);
 
     Vector vq6(0.2, 0.3, -0.2);
     PositionInBuilding q6;
     q6.pos = vq6;
     q6.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(q6, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q6, b2), TestCase::Duration::QUICK);
 
     Vector vq7(0.2, 0.3, 2.001);
     PositionInBuilding q7;
     q7.pos = vq7;
     q7.indoor = false;
-    AddTestCase(new BuildingsHelperOneTestCase(q7, b2), TestCase::QUICK);
+    AddTestCase(new BuildingsHelperOneTestCase(q7, b2), TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-pathloss-test.cc ns-3.42/src/buildings/test/buildings-pathloss-test.cc
--- ns-3.41/src/buildings/test/buildings-pathloss-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-pathloss-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -41,7 +41,7 @@
  * several communication scenarios
  */
 BuildingsPathlossTestSuite::BuildingsPathlossTestSuite()
-    : TestSuite("buildings-pathloss-test", SYSTEM)
+    : TestSuite("buildings-pathloss-test", Type::SYSTEM)
 {
     LogComponentEnable("BuildingsPathlossTest", LOG_LEVEL_ALL);
 
@@ -54,7 +54,7 @@
                                               LargeCity,
                                               137.93,
                                               "OH Urban Large city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new BuildingsPathlossTestCase(freq,
                                               1,
@@ -63,7 +63,7 @@
                                               SmallCity,
                                               137.88,
                                               "OH Urban small city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new BuildingsPathlossTestCase(freq,
                                               1,
@@ -72,7 +72,7 @@
                                               LargeCity,
                                               128.03,
                                               "loss OH SubUrban"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new BuildingsPathlossTestCase(freq,
                                               1,
@@ -81,7 +81,7 @@
                                               LargeCity,
                                               110.21,
                                               "loss OH OpenAreas"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #2 COST231 Model (1500 < freq < 2000~2170 MHz) (Macro<->UE)
 
@@ -94,7 +94,7 @@
                                               LargeCity,
                                               148.55,
                                               "COST231 Urban Large city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new BuildingsPathlossTestCase(freq,
                                               1,
@@ -103,7 +103,7 @@
                                               SmallCity,
                                               150.64,
                                               "COST231 Urban small city and suburban"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #3 2.6 GHz model (Macro<->UE)
 
@@ -116,7 +116,7 @@
                                               SmallCity,
                                               121.83,
                                               "2.6GHz model"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #4 ITU1411 LOS model (Macro<->UE)
 
@@ -128,7 +128,7 @@
                                               LargeCity,
                                               81.00,
                                               "ITU1411 LOS"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #5 ITU1411 NLOS model (Macro<->UE)
 
@@ -141,14 +141,14 @@
                                               LargeCity,
                                               143.69,
                                               "ITU1411 NLOS"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #6 ITUP1238 (HeNB <-> UE)
 
     freq = 2.1140e9; // E_UTRA BAND #1 see table 5.5-1 of 36.101
     AddTestCase(
         new BuildingsPathlossTestCase(freq, 5, 6, UrbanEnvironment, LargeCity, 88.3855, "ITUP1238"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // Test #7 Outdoor -> Indoor OkumuraHata (Macro<->UE)
 
@@ -162,7 +162,7 @@
                                               LargeCity,
                                               155.55,
                                               "Okumura Hata Outdoor -> Indoor"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #8 Outdoor -> Indoor ITU1411 (Macro<->UE)
     freq = 2.1140e9; // E_UTRA BAND #1 see table 5.5-1 of 36.101
@@ -175,7 +175,7 @@
                                               LargeCity,
                                               88.000,
                                               "ITU1411 LOS Outdoor -> Indoor"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #9 Indoor -> Outdoor LOS (HeNB <-> UE)
 
@@ -190,7 +190,7 @@
                                               LargeCity,
                                               84.838,
                                               "ITU1411 LOS Indoor -> Outdoor"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #10 Indoor -> Outdoor NLOS (HeNB <-> UE)
 
@@ -205,7 +205,7 @@
                                               LargeCity,
                                               183.90,
                                               "ITU1411 NLOS Indoor -> Outdoor"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-pathloss-test.h ns-3.42/src/buildings/test/buildings-pathloss-test.h
--- ns-3.41/src/buildings/test/buildings-pathloss-test.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-pathloss-test.h	2024-05-29 15:29:46.924073000 -0700
@@ -27,7 +27,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test 1.1 BuildingsPathlossModel Pathloss compound test
  *
@@ -42,7 +41,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test 1.1 BuildingsPathlossModel Pathloss test
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-penetration-loss-pathloss-test.cc ns-3.42/src/buildings/test/buildings-penetration-loss-pathloss-test.cc
--- ns-3.41/src/buildings/test/buildings-penetration-loss-pathloss-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-penetration-loss-pathloss-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -79,7 +79,6 @@
         Vector m_positionA; //!< the position of the first node
         Vector m_positionB; //!< the position of the second node
         double m_frequency; //!< carrier frequency in Hz
-        bool m_isLos;       //!< LOS probability
         TypeId m_condModel; //!< the type ID of the channel condition model to be used
         TypeId m_propModel; //!< the type ID of the propagation loss model to be used
         double m_pt;        //!< transmitted power in dBm
@@ -271,9 +270,9 @@
 };
 
 BuildingsPenetrationLossesTestSuite::BuildingsPenetrationLossesTestSuite()
-    : TestSuite("buildings-penetration-losses", UNIT)
+    : TestSuite("buildings-penetration-losses", Type::UNIT)
 {
-    AddTestCase(new BuildingsPenetrationLossesTestCase, TestCase::QUICK);
+    AddTestCase(new BuildingsPenetrationLossesTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-shadowing-test.cc ns-3.42/src/buildings/test/buildings-shadowing-test.cc
--- ns-3.41/src/buildings/test/buildings-shadowing-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-shadowing-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -45,21 +45,21 @@
  */
 
 BuildingsShadowingTestSuite::BuildingsShadowingTestSuite()
-    : TestSuite("buildings-shadowing-test", SYSTEM)
+    : TestSuite("buildings-shadowing-test", Type::SYSTEM)
 {
     LogComponentEnable("BuildingsShadowingTest", LOG_LEVEL_ALL);
 
     // Test #1 Outdoor Model
     AddTestCase(new BuildingsShadowingTestCase(1, 2, 148.86, 7.0, "Outdoor Shadowing"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #2 Indoor model
     AddTestCase(new BuildingsShadowingTestCase(5, 6, 88.5724, 8.0, "Indoor Shadowing"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test #3 Indoor -> Outdoor
     AddTestCase(new BuildingsShadowingTestCase(9, 10, 85.0012, 8.6, "Indoor -> Outdoor Shadowing"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/buildings-shadowing-test.h ns-3.42/src/buildings/test/buildings-shadowing-test.h
--- ns-3.41/src/buildings/test/buildings-shadowing-test.h	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/buildings-shadowing-test.h	2024-05-29 15:29:46.924073000 -0700
@@ -32,7 +32,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Shadowing compound test
  *
@@ -47,7 +46,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Shadowing test
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/outdoor-random-walk-test.cc ns-3.42/src/buildings/test/outdoor-random-walk-test.cc
--- ns-3.41/src/buildings/test/outdoor-random-walk-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/outdoor-random-walk-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -35,7 +35,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test case for the class OutdoorRandomWalkTestCase. It checks if the
  * positions visited by the user are outside buildings
@@ -164,7 +163,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test suite for the buildings channel condition model
  */
@@ -175,9 +173,9 @@
 };
 
 OutdoorRandomWalkTestSuite::OutdoorRandomWalkTestSuite()
-    : TestSuite("outdoor-random-walk-model", UNIT)
+    : TestSuite("outdoor-random-walk-model", Type::UNIT)
 {
-    AddTestCase(new OutdoorRandomWalkTestCase, TestCase::QUICK);
+    AddTestCase(new OutdoorRandomWalkTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc ns-3.42/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc
--- ns-3.41/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc	2024-02-09 14:44:07.865790000 -0800
+++ ns-3.42/src/buildings/test/three-gpp-v2v-channel-condition-model-test.cc	2024-05-29 15:29:46.924073000 -0700
@@ -38,7 +38,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test case for the classes ThreeGppV2vUrbanChannelConditionModel,
  * and ThreeGppV2vHighwayChannelConditionModel to test their code to
@@ -511,7 +510,6 @@
 
 /**
  * \ingroup building-test
- * \ingroup tests
  *
  * Test suite for the 3GPP V2V channel condition model
  *
@@ -539,17 +537,17 @@
 };
 
 ThreeGppV2vChCondModelsTestSuite::ThreeGppV2vChCondModelsTestSuite()
-    : TestSuite("three-gpp-v2v-channel-condition-model", SYSTEM)
+    : TestSuite("three-gpp-v2v-channel-condition-model", Type::SYSTEM)
 {
     AddTestCase(new ThreeGppV2vBuildingsChCondModelTestCase,
-                TestCase::QUICK); // test for the deterministic procedure (NLOS vs LOS/NLOSv), based
-                                  // on buildings
+                TestCase::Duration::QUICK); // test for the deterministic procedure (NLOS vs
+                                            // LOS/NLOSv), based on buildings
     AddTestCase(new ThreeGppV2vUrbanLosNlosvChCondModelTestCase,
-                TestCase::QUICK); // test for the probabilistic procedure (LOS vs NLOSv), in V2V
-                                  // urban scenario
+                TestCase::Duration::QUICK); // test for the probabilistic procedure (LOS vs
+                                            // NLOSv), in V2V urban scenario
     AddTestCase(new ThreeGppV2vHighwayLosNlosvChCondModelTestCase,
-                TestCase::QUICK); // test for the probabilistic procedure (LOS vs NLOSv), in V2V
-                                  // highway scenario
+                TestCase::Duration::QUICK); // test for the probabilistic procedure (LOS vs
+                                            // NLOSv), in V2V highway scenario
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/click/test/ipv4-click-routing-test.cc ns-3.42/src/click/test/ipv4-click-routing-test.cc
--- ns-3.41/src/click/test/ipv4-click-routing-test.cc	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/click/test/ipv4-click-routing-test.cc	2024-05-29 15:29:46.928073200 -0700
@@ -31,12 +31,18 @@
 using namespace ns3;
 
 /**
+ * \ingroup click
+ * \defgroup click-tests click module tests
+ */
+
+/**
  * \file
  * \ingroup click-tests
  * Click test suite.
  */
 
 /**
+ * \ingroup click-tests
  * Add Click Internet stack.
  *
  * \param node Node.
@@ -50,6 +56,7 @@
 }
 
 /**
+ * \ingroup click-tests
  * Add network device.
  *
  * \param node Node.
@@ -243,11 +250,11 @@
 {
   public:
     ClickIfidFromNameTestSuite()
-        : TestSuite("routing-click", UNIT)
+        : TestSuite("routing-click", Type::UNIT)
     {
-        AddTestCase(new ClickTrivialTest, TestCase::QUICK);
-        AddTestCase(new ClickIfidFromNameTest, TestCase::QUICK);
-        AddTestCase(new ClickIpMacAddressFromNameTest, TestCase::QUICK);
+        AddTestCase(new ClickTrivialTest, TestCase::Duration::QUICK);
+        AddTestCase(new ClickIfidFromNameTest, TestCase::Duration::QUICK);
+        AddTestCase(new ClickIpMacAddressFromNameTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/CMakeLists.txt ns-3.42/src/CMakeLists.txt
--- ns-3.41/src/CMakeLists.txt	2024-02-09 14:44:07.845789700 -0800
+++ ns-3.42/src/CMakeLists.txt	2024-05-29 15:29:46.916073000 -0700
@@ -21,6 +21,38 @@
   endif()
 endforeach()
 
+# Scan for disabled modules that define settings prefixed with NS3_ or ENABLE_
+# so that we can initialize them as turned off (setting as temporary variables
+# not to affect the cached variables that are set when normally processed)
+subdirlist(modules ${CMAKE_CURRENT_SOURCE_DIR})
+foreach(libname ${modules})
+  if(NOT (${libname} IN_LIST libs))
+    # Skip module directories without CMakeLists.txt files
+    if(NOT (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${libname}/CMakeLists.txt))
+      continue()
+    endif()
+
+    file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${libname}/CMakeLists.txt
+         lib_cmakelists_contents
+    )
+    string(REGEX MATCHALL "(NS3_[a-zA-Z0-9_]*)|(ENABLE_[a-zA-Z0-9_]*)" flags
+                 "${lib_cmakelists_contents}"
+    )
+    foreach(flag ${flags})
+      # Skip reason flags
+      if(${flag} MATCHES "REASON")
+        continue()
+      endif()
+      # Skip flags already defined
+      if(DEFINED ${flag})
+        continue()
+      endif()
+      # Set flag to off
+      set(${flag} OFF PARENT_SCOPE)
+    endforeach()
+  endif()
+endforeach()
+
 # Prevents link errors due to symbol collisions if the same library is linked
 # multiple times
 list(REMOVE_DUPLICATES ns3-external-libs)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/config-store/examples/config-store-save.cc ns-3.42/src/config-store/examples/config-store-save.cc
--- ns-3.41/src/config-store/examples/config-store-save.cc	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/config-store/examples/config-store-save.cc	2024-05-29 15:29:46.928073200 -0700
@@ -6,8 +6,13 @@
 using namespace ns3;
 
 /**
- * \ingroup configstore-examples
+ * \defgroup configstore-examples Config Store examples
+ * \ingroup configstore
  * \ingroup examples
+ */
+
+/**
+ * \ingroup configstore-examples
  *
  * \brief Example class to demonstrate use of the ns-3 Config Store
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/config-store/model/display-functions.cc ns-3.42/src/config-store/model/display-functions.cc
--- ns-3.41/src/config-store/model/display-functions.cc	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/config-store/model/display-functions.cc	2024-05-29 15:29:46.928073200 -0700
@@ -84,20 +84,15 @@
                      node->object->GetInstanceTypeId().GetName().c_str(),
                      nullptr);
         break;
+    case ModelNode::NODE_ATTRIBUTE:
     case ModelNode::NODE_POINTER:
-        g_object_set(renderer, "text", node->name.c_str(), nullptr);
-        break;
     case ModelNode::NODE_VECTOR:
         g_object_set(renderer, "text", node->name.c_str(), nullptr);
         break;
-    case ModelNode::NODE_VECTOR_ITEM: {
+    case ModelNode::NODE_VECTOR_ITEM:
         std::stringstream oss;
         oss << node->index;
         g_object_set(renderer, "text", oss.str().c_str(), nullptr);
-    }
-    break;
-    case ModelNode::NODE_ATTRIBUTE:
-        g_object_set(renderer, "text", node->name.c_str(), nullptr);
         break;
     }
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/CMakeLists.txt ns-3.42/src/core/CMakeLists.txt
--- ns-3.41/src/core/CMakeLists.txt	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/core/CMakeLists.txt	2024-05-29 15:29:46.928073200 -0700
@@ -137,7 +137,6 @@
     model/timer.cc
     model/watchdog.cc
     model/synchronizer.cc
-    model/make-event.cc
     model/environment-variable.cc
     model/log.cc
     model/breakpoint.cc
@@ -228,7 +227,6 @@
     model/hash-murmur3.h
     model/hash.h
     model/heap-scheduler.h
-    model/int-to-type.h
     model/int64x64-double.h
     model/int64x64.h
     model/integer.h
@@ -258,6 +256,7 @@
     model/rng-stream.h
     model/scheduler.h
     model/show-progress.h
+    model/shuffle.h
     model/simple-ref-count.h
     model/simulation-singleton.h
     model/simulator-impl.h
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/doc/deprecated-example.h ns-3.42/src/core/doc/deprecated-example.h
--- ns-3.41/src/core/doc/deprecated-example.h	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/core/doc/deprecated-example.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2015 Lawrence Livermore National Laboratory
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Authors: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
- */
-
-/*
- * This is an example included in the doxygen-generated documentation
- * for NS_DEPRECATED.
- */
-
-// [doxygen snippet]
-/*
- * Do something useful.
- *
- * \deprecated This method will go away in future versions of ns-3.
- * See instead TheNewWay()
- */
-NS_DEPRECATED_3_XX("see TheNewWay")
-void SomethingUseful();
-/*
- * Do something more useful.
- */
-void TheNewWay();
-// [doxygen snippet]
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/examples/empirical-random-variable-example.cc ns-3.42/src/core/examples/empirical-random-variable-example.cc
--- ns-3.41/src/core/examples/empirical-random-variable-example.cc	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/core/examples/empirical-random-variable-example.cc	2024-05-29 15:29:46.928073200 -0700
@@ -29,9 +29,13 @@
 #include <map>
 
 /**
- * \file
- * \ingroup core-examples randomvariable
  * \defgroup empirical-rng-example Core example: Empirical random variables use.
+ * \ingroup core-examples randomvariable
+ */
+
+/**
+ * \file
+ * \ingroup empirical-rng-example
  *
  * Example program illustrating use of ns3::EmpiricalRandomVariable
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/examples/sample-rng-plot.py ns-3.42/src/core/examples/sample-rng-plot.py
--- ns-3.41/src/core/examples/sample-rng-plot.py	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/core/examples/sample-rng-plot.py	2024-05-29 15:29:46.928073200 -0700
@@ -47,7 +47,7 @@
     # mu, var = 100, 225
 
     ## Random number generator.
-    rng = ns.CreateObject("NormalRandomVariable")
+    rng = ns.CreateObject[ns.NormalRandomVariable]()
     rng.SetAttribute("Mean", ns.DoubleValue(100.0))
     rng.SetAttribute("Variance", ns.DoubleValue(225.0))
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/examples/sample-simulator.py ns-3.42/src/core/examples/sample-simulator.py
--- ns-3.41/src/core/examples/sample-simulator.py	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/core/examples/sample-simulator.py	2024-05-29 15:29:46.928073200 -0700
@@ -38,7 +38,7 @@
 ## Example function - triggered at a random time.
 ## \return None.
 def RandomFunction():
-    print("RandomFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s")
+    print("RandomFunction received event at", ns.Simulator.Now().GetSeconds(), "s")
 
 
 ## Example function - triggered if an event is canceled (should not be called).
@@ -119,23 +119,23 @@
     cmd.Parse(argv)
 
     model = ns.cppyy.gbl.MyModel()
-    v = ns.CreateObject("UniformRandomVariable")
-    v.SetAttribute("Min", ns.core.DoubleValue(10))
-    v.SetAttribute("Max", ns.core.DoubleValue(20))
+    v = ns.CreateObject[ns.UniformRandomVariable]()
+    v.SetAttribute("Min", ns.DoubleValue(10))
+    v.SetAttribute("Max", ns.DoubleValue(20))
 
     ev = ns.cppyy.gbl.ExampleFunctionEvent(model)
-    ns.core.Simulator.Schedule(ns.core.Seconds(10.0), ev)
+    ns.Simulator.Schedule(ns.Seconds(10.0), ev)
 
     ev2 = ns.cppyy.gbl.RandomFunctionEvent(model)
-    ns.core.Simulator.Schedule(ns.core.Seconds(v.GetValue()), ev2)
+    ns.Simulator.Schedule(ns.Seconds(v.GetValue()), ev2)
 
     ev3 = ns.cppyy.gbl.CancelledFunctionEvent()
-    id = ns.core.Simulator.Schedule(ns.core.Seconds(30.0), ev3)
-    ns.core.Simulator.Cancel(id)
+    id = ns.Simulator.Schedule(ns.Seconds(30.0), ev3)
+    ns.Simulator.Cancel(id)
 
-    ns.core.Simulator.Run()
+    ns.Simulator.Run()
 
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Destroy()
 
 
 if __name__ == "__main__":
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/helper/csv-reader.cc ns-3.42/src/core/helper/csv-reader.cc
--- ns-3.41/src/core/helper/csv-reader.cc	2024-02-09 14:44:07.869789800 -0800
+++ ns-3.42/src/core/helper/csv-reader.cc	2024-05-29 15:29:46.928073200 -0700
@@ -31,7 +31,6 @@
 
 /**
  * \file
- * \ingroup core
  * \ingroup csvreader
  *
  * ns3::CsvReader implementation
@@ -460,7 +459,6 @@
         }
         break;
         case State::FIND_DELIMITER:
-            break;
         case State::END:
             break;
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/helper/csv-reader.h ns-3.42/src/core/helper/csv-reader.h
--- ns-3.41/src/core/helper/csv-reader.h	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/helper/csv-reader.h	2024-05-29 15:29:46.928073200 -0700
@@ -29,7 +29,6 @@
 
 /**
  * \file
- * \ingroup core
  * \ingroup csvreader
  *
  * ns3::CsvReader declaration
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/attribute-container.h ns-3.42/src/core/model/attribute-container.h
--- ns-3.41/src/core/model/attribute-container.h	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/attribute-container.h	2024-05-29 15:29:46.928073200 -0700
@@ -34,10 +34,18 @@
 namespace ns3
 {
 
+/*!
+ * \ingroup attributes
+ * \addtogroup attribute_AttributeContainer AttributeContainer Attribute
+ * AttributeValue implementation for AttributeContainer
+ */
+
 class AttributeChecker;
 
 // A = attribute value type, C = container type to return
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * A container for one type of attribute.
  *
  * The container uses \p A to parse items into elements.
@@ -186,11 +194,18 @@
      * \return This object with items copied.
      */
     template <class ITER>
-    Ptr<AttributeContainerValue<A, Sep, C>> CopyFrom(const ITER begin, const ITER end);
+    inline Ptr<AttributeContainerValue<A, Sep, C>> CopyFrom(const ITER begin, const ITER end);
 
     container_type m_container; //!< Internal container
 };
 
+/*!
+ * \ingroup attribute_AttributeContainer
+ *
+ * \class  ns3::AttributeContainerChecker "attribute-container.h"
+ * AttributeChecker implementation for AttributeContainerValue.
+ * \see AttributeChecker
+ */
 class AttributeContainerChecker : public AttributeChecker
 {
   public:
@@ -207,6 +222,8 @@
 };
 
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * Make AttributeContainerChecker from AttributeContainerValue.
  * @tparam A \deduced AttributeValue type in container.
  * @tparam Sep \deduced Character separator between elements for parsing.
@@ -219,6 +236,8 @@
     const AttributeContainerValue<A, Sep, C>& value);
 
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * Make AttributeContainerChecker using explicit types, initialize item checker.
  * @tparam A AttributeValue type in container.
  * @tparam Sep Character separator between elements for parsing.
@@ -230,6 +249,8 @@
 Ptr<const AttributeChecker> MakeAttributeContainerChecker(Ptr<const AttributeChecker> itemchecker);
 
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * Make uninitialized AttributeContainerChecker using explicit types.
  * @tparam A AttributeValue type in container.
  * @tparam Sep Character separator between elements for parsing.
@@ -240,6 +261,8 @@
 Ptr<AttributeChecker> MakeAttributeContainerChecker();
 
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * Make AttributeContainerAccessor  using explicit types.
  * @tparam A AttributeValue type in container.
  * @tparam Sep Character separator between elements for parsing.
@@ -254,6 +277,8 @@
 Ptr<const AttributeAccessor> MakeAttributeContainerAccessor(T1 a1);
 
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * Make AttributeContainerAccessor  using explicit types.
  * @tparam A AttributeValue type in container.
  * @tparam Sep Character separator between elements for parsing.
@@ -287,7 +312,10 @@
 {
 
 /**
+ * \ingroup attribute_AttributeContainer
+ *
  * \internal
+ *
  * Templated AttributeContainerChecker class that is instantiated
  * in MakeAttributeContainerChecker. The non-templated base ns3::AttributeContainerChecker
  * is returned from that function. This is the same pattern as ObjectPtrContainer.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/attribute.h ns-3.42/src/core/model/attribute.h
--- ns-3.41/src/core/model/attribute.h	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/attribute.h	2024-05-29 15:29:46.928073200 -0700
@@ -226,9 +226,17 @@
 };
 
 /**
+ * \ingroup attributes
+ * \defgroup attribute_EmptyAttribute EmptyAttribute Attribute
+ * AttributeValue implementation for EmptyAttribute
+ */
+
+/**
  * \brief A class for an empty attribute value.
  *
- * \ingroup attributes
+ * \ingroup attribute_EmptyAttribute
+ *
+ * \see AttributeValue
  */
 class EmptyAttributeValue : public AttributeValue
 {
@@ -262,6 +270,8 @@
 /**
  * \brief An accessor for EmptyAttributeValue
  *
+ * \ingroup attribute_EmptyAttribute
+ *
  * Does nothing, since every EmptyAttributeValue is the same.
  */
 class EmptyAttributeAccessor : public AttributeAccessor
@@ -276,7 +286,7 @@
 };
 
 /**
- * \ingroup attributes
+ * \ingroup attribute_EmptyAttribute
  *
  * \brief Create an empty AttributeAccessor.
  *
@@ -291,6 +301,8 @@
 /**
  * \brief A checker for EmptyAttributeValue
  *
+ * \ingroup attribute_EmptyAttribute
+ *
  * Does nothing, since every EmptyAttributeValue does not contain anything and
  * is, of course, valid.
  */
@@ -308,7 +320,7 @@
 };
 
 /**
- * \ingroup attributes
+ * \ingroup attribute_EmptyAttribute
  *
  * \brief Create an empty AttributeChecker.
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/boolean.cc ns-3.42/src/core/model/boolean.cc
--- ns-3.41/src/core/model/boolean.cc	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/boolean.cc	2024-05-29 15:29:46.928073200 -0700
@@ -24,7 +24,7 @@
 /**
  * \file
  * \ingroup attribute_Boolean
- * ns3::BooleanValue attribute value implementaation.
+ * ns3::BooleanValue attribute value implementation.
  */
 
 namespace ns3
@@ -38,7 +38,7 @@
     NS_LOG_FUNCTION(this);
 }
 
-BooleanValue::BooleanValue(bool value)
+BooleanValue::BooleanValue(const bool& value)
     : m_value(value)
 {
     NS_LOG_FUNCTION(this << value);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/boolean.h ns-3.42/src/core/model/boolean.h
--- ns-3.41/src/core/model/boolean.h	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/boolean.h	2024-05-29 15:29:46.928073200 -0700
@@ -37,12 +37,7 @@
 {
   public:
     BooleanValue();
-    /**
-     * Construct from an explicit value.
-     *
-     * \param [in] value The boolean value to begin with.
-     */
-    BooleanValue(bool value);
+    BooleanValue(const bool& value);
     void Set(bool value);
     bool Get() const;
     template <typename T>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/callback.cc ns-3.42/src/core/model/callback.cc
--- ns-3.41/src/core/model/callback.cc	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/callback.cc	2024-05-29 15:29:46.928073200 -0700
@@ -38,8 +38,8 @@
     NS_LOG_FUNCTION(this);
 }
 
-CallbackValue::CallbackValue(const CallbackBase& base)
-    : m_value(base)
+CallbackValue::CallbackValue(const CallbackBase& value)
+    : m_value(value)
 {
 }
 
@@ -49,11 +49,17 @@
 }
 
 void
-CallbackValue::Set(CallbackBase base)
+CallbackValue::Set(const CallbackBase& value)
 {
-    NS_LOG_FUNCTION(&base);
+    NS_LOG_FUNCTION(&value);
+    m_value = value;
+}
 
-    m_value = base;
+CallbackBase
+CallbackValue::Get()
+{
+    NS_LOG_FUNCTION(this);
+    return m_value;
 }
 
 Ptr<AttributeValue>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/callback.h ns-3.42/src/core/model/callback.h
--- ns-3.41/src/core/model/callback.h	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/callback.h	2024-05-29 15:29:46.928073200 -0700
@@ -490,8 +490,10 @@
      * of the first argument is a class derived from CallbackBase (i.e., a Callback).
      */
     template <typename T,
-              std::enable_if_t<!std::is_base_of_v<CallbackBase, T>, int> = 0,
-              typename... BArgs>
+              typename... BArgs,
+              std::enable_if_t<!std::is_base_of_v<CallbackBase, T> &&
+                                   std::is_invocable_r_v<R, T, BArgs..., UArgs...>,
+                               int> = 0>
     Callback(T func, BArgs... bargs)
     {
         // store the function in a std::function object
@@ -648,18 +650,12 @@
      */
     bool DoCheckType(Ptr<const CallbackImplBase> other) const
     {
-        if (other && dynamic_cast<const CallbackImpl<R, UArgs...>*>(PeekPointer(other)) != nullptr)
+        if (!other)
         {
             return true;
         }
-        else if (!other)
-        {
-            return true;
-        }
-        else
-        {
-            return false;
-        }
+
+        return (dynamic_cast<const CallbackImpl<R, UArgs...>*>(PeekPointer(other)) != nullptr);
     }
 };
 
@@ -805,18 +801,12 @@
 class CallbackValue : public AttributeValue
 {
   public:
-    /** Constructor */
     CallbackValue();
-    /**
-     * Copy constructor
-     * \param [in] base Callback to copy
-     */
-    CallbackValue(const CallbackBase& base);
-    /** Destructor */
+    CallbackValue(const CallbackBase& value);
     ~CallbackValue() override;
-    /** \param [in] base The CallbackBase to use */
-    void Set(CallbackBase base);
-    /* Documented by print-introspected-doxygen.cc */
+    // Documented by print-introspected-doxygen.cc
+    void Set(const CallbackBase& value);
+    CallbackBase Get();
     template <typename T>
     bool GetAccessor(T& value) const;
     /** \return A copy of this CallBack */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/config.cc ns-3.42/src/core/model/config.cc
--- ns-3.41/src/core/model/config.cc	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/config.cc	2024-05-29 15:29:46.932073000 -0700
@@ -30,10 +30,14 @@
 
 /**
  * \file
- * \ingroup config
+ * \ingroup config-impl
  * ns3::Config implementations.
  */
 
+/**
+ * \defgroup config-impl Config implementations
+ * \ingroup config
+ */
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/deprecated.h ns-3.42/src/core/model/deprecated.h
--- ns-3.41/src/core/model/deprecated.h	2024-02-09 14:44:07.873789800 -0800
+++ ns-3.42/src/core/model/deprecated.h	2024-05-29 15:29:46.932073000 -0700
@@ -22,12 +22,17 @@
 
 /**
  * \file
- * \ingroup core
+ * \ingroup deprecation
  * NS_DEPRECATED macro definition.
  */
 
 /**
+ * \defgroup deprecation Deprecation
  * \ingroup core
+ */
+
+/**
+ * \ingroup deprecation
  * \def NS_DEPRECATED
  * Mark a function as deprecated.
  *
@@ -36,8 +41,22 @@
  * When deprecating a feature, please update the documentation
  * with information for users on how to update their code.
  *
- * For example,
- * \snippet src/core/doc/deprecated-example.h doxygen snippet
+ * The following snippet shows an example of how to deprecate the function SomethingUseful()
+ * in favor of the new function TheNewWay().
+ * Note: in the following snippet, the Doxygen blocks are not following the ns-3 style.
+ * This allows the code to be safely embedded in the documentation.
+ *
+ * \code
+ * /// Do something useful.
+ * ///
+ * /// \deprecated This method will go away in future versions of ns-3.
+ * /// See instead TheNewWay().
+ * NS_DEPRECATED_3_XX("see TheNewWay")
+ * void SomethingUseful();
+ *
+ * /// Do something more useful.
+ * void TheNewWay();
+ * \endcode
  *
  * Please follow these two guidelines to ease future maintenance
  * (primarily the eventual removal of the deprecated code):
@@ -48,7 +67,8 @@
  * 2.  Typically only the declaration needs to be deprecated,
  *
  *     \code
- *     NS_DEPRECATED_3_XX ("see TheNewWay") void SomethingUseful ();
+ *     NS_DEPRECATED_3_XX("see TheNewWay")
+ *     void SomethingUseful();
  *     \endcode
  *
  *     but it's helpful to put the same macro as a comment
@@ -56,9 +76,9 @@
  *     all the bits which eventually have to be removed:
  *
  *     \code
- *     \/\* NS_DEPRECATED_3_XX ("see TheNewWay") *\\/
- *     void SomethingUseful () { ... }
- *     \endcode.
+ *     // NS_DEPRECATED_3_XX("see TheNewWay")
+ *     void SomethingUseful() { ... }
+ *     \endcode
  *
  * \note Sometimes it is necessary to silence a deprecation warning.
  * Even though this is highly discouraged, if necessary it is possible to use:
@@ -75,17 +95,24 @@
 #define NS_DEPRECATED(msg) [[deprecated(msg)]]
 
 /**
- * \ingroup core
+ * \ingroup deprecation
+ * \def NS_DEPRECATED_3_42
+ * Tag for things deprecated in version ns-3.42.
+ */
+#define NS_DEPRECATED_3_42(msg) NS_DEPRECATED("Deprecated in ns-3.42: " msg)
+
+/**
+ * \ingroup deprecation
  * \def NS_DEPRECATED_3_41
  * Tag for things deprecated in version ns-3.41.
  */
-#define NS_DEPRECATED_3_41(msg) NS_DEPRECATED(msg)
+#define NS_DEPRECATED_3_41(msg) NS_DEPRECATED("Deprecated in ns-3.41: " msg)
 
 /**
- * \ingroup core
+ * \ingroup deprecation
  * \def NS_DEPRECATED_3_40
  * Tag for things deprecated in version ns-3.40.
  */
-#define NS_DEPRECATED_3_40(msg) NS_DEPRECATED(msg)
+#define NS_DEPRECATED_3_40(msg) NS_DEPRECATED("Deprecated in ns-3.40: " msg)
 
 #endif /* NS3_DEPRECATED_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/enum.h ns-3.42/src/core/model/enum.h
--- ns-3.41/src/core/model/enum.h	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/enum.h	2024-05-29 15:29:46.932073000 -0700
@@ -62,12 +62,7 @@
 {
   public:
     EnumValue();
-    /**
-     * Construct from an explicit value.
-     *
-     * \param [in] value The value to begin with.
-     */
-    EnumValue(T value);
+    EnumValue(const T& value);
     void Set(T value);
     T Get() const;
 
@@ -78,14 +73,14 @@
     bool DeserializeFromString(std::string value, Ptr<const AttributeChecker> checker) override;
 
   private:
-    T m_value; //!< The stored value.
+    T m_value{}; //!< The stored value.
 };
 
 template <typename T>
 EnumValue<T>::EnumValue() = default;
 
 template <typename T>
-EnumValue<T>::EnumValue(T value)
+EnumValue<T>::EnumValue(const T& value)
     : m_value(value)
 {
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/event-id.cc ns-3.42/src/core/model/event-id.cc
--- ns-3.41/src/core/model/event-id.cc	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/event-id.cc	2024-05-29 15:29:46.932073000 -0700
@@ -73,12 +73,18 @@
 }
 
 bool
-EventId::IsRunning() const
+EventId::IsPending() const
 {
     NS_LOG_FUNCTION(this);
     return !IsExpired();
 }
 
+bool
+EventId::IsRunning() const
+{
+    return IsPending();
+}
+
 EventImpl*
 EventId::PeekEventImpl() const
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/event-id.h ns-3.42/src/core/model/event-id.h
--- ns-3.41/src/core/model/event-id.h	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/event-id.h	2024-05-29 15:29:46.932073000 -0700
@@ -19,6 +19,7 @@
 #ifndef EVENT_ID_H
 #define EVENT_ID_H
 
+#include "deprecated.h"
 #include "event-impl.h"
 #include "ptr.h"
 
@@ -47,7 +48,7 @@
  * The important thing to remember about this class is that
  * every variable of this type is _always_ in a valid state,
  * even when it has not been assigned an EventId coming from a
- * Simulator::Schedule() method:  calling Simulator::Cancel(), IsRunning(),
+ * Simulator::Schedule() method:  calling Simulator::Cancel(), IsPending(),
  * IsExpired() or passing around instances of this object
  * will not result in crashes or memory leaks.
  */
@@ -101,6 +102,14 @@
      *
      * \returns \c true if the event has not expired, \c false otherwise.
      */
+    bool IsPending() const;
+
+    /**
+     * This method is syntactic sugar for !IsExpired().
+     *
+     * \returns \c true if the event has not expired, \c false otherwise.
+     */
+    NS_DEPRECATED_3_42("Use IsPending instead")
     bool IsRunning() const;
 
   public:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/example-as-test.cc ns-3.42/src/core/model/example-as-test.cc
--- ns-3.41/src/core/model/example-as-test.cc	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/example-as-test.cc	2024-05-29 15:29:46.932073000 -0700
@@ -153,9 +153,9 @@
                                        const std::string program,
                                        const std::string dataDir,
                                        const std::string args /* = "" */,
-                                       const TestDuration duration /* =QUICK */,
+                                       const Duration duration /* =QUICK */,
                                        const bool shouldNotErr /* = true */)
-    : TestSuite(name, EXAMPLE)
+    : TestSuite(name, Type::EXAMPLE)
 {
     NS_LOG_FUNCTION(this << name << program << dataDir << args << duration << shouldNotErr);
     AddTestCase(new ExampleAsTestCase(name, program, dataDir, args, shouldNotErr), duration);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/example-as-test.h ns-3.42/src/core/model/example-as-test.h
--- ns-3.41/src/core/model/example-as-test.h	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/example-as-test.h	2024-05-29 15:29:46.932073000 -0700
@@ -218,7 +218,7 @@
                        const std::string program,
                        const std::string dataDir,
                        const std::string args = "",
-                       const TestDuration duration = QUICK,
+                       const Duration duration = Duration::QUICK,
                        const bool shouldNotErr = true);
 }; // class ExampleAsTestSuite
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/global-value.h ns-3.42/src/core/model/global-value.h
--- ns-3.41/src/core/model/global-value.h	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/global-value.h	2024-05-29 15:29:46.932073000 -0700
@@ -41,7 +41,7 @@
 }
 
 /**
- * \ingroup Core
+ * \ingroup core
  *
  * \brief Hold a so-called 'global value'.
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/int64x64-128.cc ns-3.42/src/core/model/int64x64-128.cc
--- ns-3.41/src/core/model/int64x64-128.cc	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/int64x64-128.cc	2024-05-29 15:29:46.932073000 -0700
@@ -52,8 +52,8 @@
 {
     bool negA = sa < 0;
     bool negB = sb < 0;
-    ua = negA ? -sa : sa;
-    ub = negB ? -sb : sb;
+    ua = negA ? -static_cast<uint128_t>(sa) : sa;
+    ub = negB ? -static_cast<uint128_t>(sb) : sb;
     return negA != negB;
 }
 
@@ -64,50 +64,64 @@
     uint128_t b;
     bool negative = output_sign(_v, o._v, a, b);
     uint128_t result = Umul(a, b);
-    _v = negative ? -result : result;
+    if (negative)
+    {
+        NS_ASSERT_MSG(result <= HP128_MASK_HI_BIT, "overflow detected");
+        _v = -result;
+    }
+    else
+    {
+        NS_ASSERT_MSG(result < HP128_MASK_HI_BIT, "overflow detected");
+        _v = result;
+    }
 }
 
 uint128_t
 int64x64_t::Umul(const uint128_t a, const uint128_t b)
 {
-    uint128_t aL = a & HP_MASK_LO;
-    uint128_t bL = b & HP_MASK_LO;
-    uint128_t aH = (a >> 64) & HP_MASK_LO;
-    uint128_t bH = (b >> 64) & HP_MASK_LO;
-
-    uint128_t result;
-    uint128_t hiPart;
-    uint128_t loPart;
-    uint128_t midPart;
-    uint128_t res1;
-    uint128_t res2;
-
-    // Multiplying (a.h 2^64 + a.l) x (b.h 2^64 + b.l) =
-    //             2^128 a.h b.h + 2^64*(a.h b.l+b.h a.l) + a.l b.l
-    // get the low part a.l b.l
-    // multiply the fractional part
-    loPart = aL * bL;
-    // compute the middle part 2^64*(a.h b.l+b.h a.l)
-    midPart = aL * bH + aH * bL;
-    // compute the high part 2^128 a.h b.h
-    hiPart = aH * bH;
-    // if the high part is not zero, put a warning
-    NS_ABORT_MSG_IF((hiPart & HP_MASK_HI) != 0,
-                    "High precision 128 bits multiplication error: multiplication overflow.");
-
-    // Adding 64-bit terms to get 128-bit results, with carries
-    res1 = loPart >> 64;
-    res2 = midPart & HP_MASK_LO;
-    result = res1 + res2;
-
-    res1 = midPart >> 64;
-    res2 = hiPart & HP_MASK_LO;
-    res1 += res2;
-    res1 <<= 64;
+    uint128_t al = a & HP_MASK_LO;
+    uint128_t bl = b & HP_MASK_LO;
+    uint128_t ah = a >> 64;
+    uint128_t bh = b >> 64;
+
+    // Let Q(x) be the unsigned Q64.64 fixed point value represented by the uint128_t x:
+    //     Q(x) * 2^64 = x = xh * 2^64 + xl.
+    // (Defining x this way avoids ambiguity about the meaning of the division operators in
+    //     Q(x) = x / 2^64 = xh + xl / 2^64.)
+    // Then
+    //     Q(a) = ah + al / 2^64
+    // and
+    //     Q(b) = bh + bl / 2^64.
+    // We need to find uint128_t c such that
+    //     Q(c) = Q(a) * Q(b).
+    // Then
+    //     c = Q(c) * 2^64
+    //       = (ah + al / 2^64) * (bh + bl / 2^64) * 2^64
+    //       = (ah * 2^64 + al) * (bh * 2^64 + bl) / 2^64
+    //       = ah * bh * 2^64 + (ah * bl + al * bh) + al * bl / 2^64.
+    // We compute the last part of c by (al * bl) >> 64 which truncates (instead of rounds)
+    // the LSB. If c exceeds 2^127, we might assert. This is because our caller
+    // (Mul function) will not be able to represent the result.
 
-    result += res1;
+    uint128_t res = (al * bl) >> 64;
+    {
+        // ah, bh <= 2^63 and al, bl <= 2^64 - 1, so mid < 2^128 - 2^64 and there is no
+        // integer overflow.
+        uint128_t mid = ah * bl + al * bh;
+        // res < 2^64, so there is no integer overflow.
+        res += mid;
+    }
+    {
+        uint128_t high = ah * bh;
+        // If high > 2^63, then the result will overflow.
+        NS_ASSERT_MSG(high <= (static_cast<uint128_t>(1) << 63), "overflow detected");
+        high <<= 64;
+        NS_ASSERT_MSG(res + high >= res, "overflow detected");
+        // No overflow since res, high <= 2^127 and one of res, high is < 2^127.
+        res += high;
+    }
 
-    return result;
+    return res;
 }
 
 void
@@ -189,7 +203,7 @@
 int64x64_t::MulByInvert(const int64x64_t& o)
 {
     bool negResult = _v < 0;
-    uint128_t a = negResult ? -_v : _v;
+    uint128_t a = negResult ? -static_cast<uint128_t>(_v) : _v;
     uint128_t result = UmulByInvert(a, o._v);
 
     _v = negResult ? -result : result;
@@ -198,21 +212,25 @@
 uint128_t
 int64x64_t::UmulByInvert(const uint128_t a, const uint128_t b)
 {
-    uint128_t result;
-    uint128_t ah;
-    uint128_t bh;
-    uint128_t al;
-    uint128_t bl;
-    uint128_t hi;
-    uint128_t mid;
-    ah = a >> 64;
-    bh = b >> 64;
-    al = a & HP_MASK_LO;
-    bl = b & HP_MASK_LO;
-    hi = ah * bh;
-    mid = ah * bl + al * bh;
+    // Since b is assumed to be the output of Invert(), b <= 2^127.
+    NS_ASSERT(b <= HP128_MASK_HI_BIT);
+
+    uint128_t al = a & HP_MASK_LO;
+    uint128_t bl = b & HP_MASK_LO;
+    uint128_t ah = a >> 64;
+    uint128_t bh = b >> 64;
+
+    // Since ah, bh <= 2^63, high <= 2^126 and there is no overflow.
+    uint128_t high = ah * bh;
+
+    // Since ah, bh <= 2^63 and al, bl < 2^64, mid < 2^128 and there is
+    // no overflow.
+    uint128_t mid = ah * bl + al * bh;
     mid >>= 64;
-    result = hi + mid;
+
+    // Since high <= 2^126 and mid < 2^64, result < 2^127 and there is no overflow.
+    uint128_t result = high + mid;
+
     return result;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/int64x64-128.h ns-3.42/src/core/model/int64x64-128.h
--- ns-3.41/src/core/model/int64x64-128.h	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/int64x64-128.h	2024-05-29 15:29:46.932073000 -0700
@@ -58,8 +58,6 @@
     static const uint128_t HP128_MASK_HI_BIT = (((int128_t)1) << 127);
     /// Mask for fraction part.
     static const uint64_t HP_MASK_LO = 0xffffffffffffffffULL;
-    /// Mask for sign + integer part.
-    static const uint64_t HP_MASK_HI = ~HP_MASK_LO;
     /**
      * Floating point value of HP_MASK_LO + 1.
      * We really want:
@@ -190,11 +188,6 @@
         _v <<= 64;
     }
 
-    inline int64x64_t(const int128_t v)
-        : _v(v)
-    {
-    }
-
     /**@}*/
 
     /**
@@ -403,7 +396,9 @@
 
     friend inline int64x64_t operator-(const int64x64_t& lhs)
     {
-        return int64x64_t(-lhs._v);
+        int64x64_t res;
+        res._v = -lhs._v;
+        return res;
     }
 
     friend inline int64x64_t operator!(const int64x64_t& lhs)
@@ -415,6 +410,7 @@
 
     /**
      * Implement `*=`.
+     * We assert if the product cannot be encoded in int64x64_t.
      *
      * \param [in] o The other factor.
      */
@@ -430,7 +426,7 @@
      *
      * Mathematically this should produce a Q128.128 value;
      * we keep the central 128 bits, representing the Q64.64 result.
-     * We assert on integer overflow beyond the 64-bit integer portion.
+     * We might assert if the result, in uint128_t format, exceeds 2^127.
      *
      * \param [in] a First factor.
      * \param [in] b Second factor.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/int64x64.cc ns-3.42/src/core/model/int64x64.cc
--- ns-3.41/src/core/model/int64x64.cc	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/int64x64.cc	2024-05-29 15:29:46.932073000 -0700
@@ -23,6 +23,7 @@
 
 #include <iomanip> // showpos
 #include <iostream>
+#include <limits>
 #include <sstream>
 #include <stdint.h>
 
@@ -69,9 +70,19 @@
 operator<<(std::ostream& os, const int64x64_t& value)
 {
     const bool negative = (value < 0);
-    const int64x64_t absVal = (negative ? -value : value);
 
-    int64_t hi = absVal.GetHigh();
+    uint64_t hi;
+    int64x64_t low;
+    if (value != int64x64_t(std::numeric_limits<int64_t>::min(), 0))
+    {
+        const int64x64_t absVal = (negative ? -value : value);
+        hi = absVal.GetHigh();
+        low = int64x64_t(0, absVal.GetLow());
+    }
+    else
+    {
+        hi = static_cast<uint64_t>(1) << 63;
+    }
 
     // Save stream format flags
     auto precision = static_cast<std::size_t>(os.precision());
@@ -84,7 +95,6 @@
     std::ostringstream oss;
     oss << hi << "."; // collect the digits here so we can round properly
 
-    int64x64_t low(0, absVal.GetLow());
     std::size_t places = 0; // Number of decimal places printed so far
     bool more = true;       // Should we print more digits?
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/int-to-type.h ns-3.42/src/core/model/int-to-type.h
--- ns-3.41/src/core/model/int-to-type.h	2024-02-09 14:44:07.877790000 -0800
+++ ns-3.42/src/core/model/int-to-type.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2007 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#ifndef INT_TO_TYPE_H
-#define INT_TO_TYPE_H
-
-/**
- * \file
- * ns3::IntToType template class.
- */
-
-namespace ns3
-{
-
-/**
- * Convert an integer into a type.
- *
- * This trivial template is extremely useful, as explained in
- * "Modern C++ Design", p 29, section 2.4,
- * "Mapping Integral Constants to Types".
- *
- * For an example, see timer-impl.h
- *
- * \tparam v \explicit The integral constant value distinguishing this type
- *           from other values.
- */
-template <int v>
-struct IntToType
-{
-    /** Enumeration holding the type-specific value. */
-    enum v_e
-    {
-        value = v /**< The integer value distinguishing this type. */
-    };
-};
-
-} // namespace ns3
-
-#endif /* INT_TO_TYPE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/make-event.cc ns-3.42/src/core/model/make-event.cc
--- ns-3.41/src/core/model/make-event.cc	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/make-event.cc	1969-12-31 16:00:00.000000000 -0800
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2008 INRIA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include "make-event.h"
-
-#include "log.h"
-
-/**
- * \file
- * \ingroup events
- * ns3::MakeEvent(void(*f)()) implementation.
- */
-
-namespace ns3
-{
-
-NS_LOG_COMPONENT_DEFINE("MakeEvent");
-
-// This is the only non-templated version of MakeEvent.
-EventImpl*
-MakeEvent(void (*f)())
-{
-    NS_LOG_FUNCTION(f);
-
-    // zero arg version
-    class EventFunctionImpl0 : public EventImpl
-    {
-      public:
-        typedef void (*F)();
-
-        EventFunctionImpl0(F function)
-            : m_function(function)
-        {
-        }
-
-        ~EventFunctionImpl0() override
-        {
-        }
-
-      protected:
-        void Notify() override
-        {
-            (*m_function)();
-        }
-
-      private:
-        F m_function;
-    }* ev = new EventFunctionImpl0(f);
-
-    return ev;
-}
-
-} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/make-event.h ns-3.42/src/core/model/make-event.h
--- ns-3.41/src/core/model/make-event.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/make-event.h	2024-05-29 15:29:46.932073000 -0700
@@ -19,6 +19,12 @@
 #ifndef MAKE_EVENT_H
 #define MAKE_EVENT_H
 
+#include "warnings.h"
+
+#include <functional>
+#include <tuple>
+#include <type_traits>
+
 /**
  * \file
  * \ingroup events
@@ -32,150 +38,21 @@
 
 /**
  * \ingroup events
- * \defgroup makeeventmemptr MakeEvent from Member Function Pointer.
- *
- * Create EventImpl instances from class member functions which take
- * varying numbers of arguments.
- */
-/**
- * \ingroup makeeventmemptr
- * @{
- */
-/**
  * Make an EventImpl from class method members which take
  * varying numbers of arguments.
  *
  * \tparam MEM \deduced The class method function signature.
  * \tparam OBJ \deduced The class type holding the method.
+ * \tparam Ts \deduced Type template parameter pack.
  * \param [in] mem_ptr Class method member function pointer
  * \param [in] obj Class instance.
+ * \param [in] args Arguments to be bound to the underlying function.
  * \returns The constructed EventImpl.
  */
-template <typename MEM, typename OBJ>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj);
-
-/**
- * \copybrief MakeEvent(MEM,OBJ)
- * \tparam MEM \deduced The class method function signature.
- * \tparam OBJ \deduced The class type holding the method.
- * \tparam T1 \deduced Type of the argument to the underlying function.
- * \param [in] mem_ptr Class method member function pointer
- * \param [in] obj Class instance.
- * \param [in] a1 Argument value to be bound to the underlying function.
- * \returns The constructed EventImpl.
- */
-template <typename MEM, typename OBJ, typename T1>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj, T1 a1);
-
-/**
- * \copybrief MakeEvent(MEM,OBJ)
- * \tparam MEM \deduced The class method function signature.
- * \tparam OBJ \deduced The class type holding the method.
- * \tparam T1 \deduced Type of the first argument to the underlying function.
- * \tparam T2 \deduced Type of the second argument to the underlying function.
- * \param [in] mem_ptr Class method member function pointer
- * \param [in] obj Class instance.
- * \param [in] a1 First argument value to be bound to the underlying function.
- * \param [in] a2 Second argument value to be bound to the underlying function.
- * \returns The constructed EventImpl.
- */
-template <typename MEM, typename OBJ, typename T1, typename T2>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
-
-/**
- * \copybrief MakeEvent(MEM,OBJ)
- * \tparam MEM \deduced The class method function signature.
- * \tparam OBJ \deduced The class type holding the method.
- * \tparam T1 \deduced Type of the first argument to the underlying function.
- * \tparam T2 \deduced Type of the second argument to the underlying function.
- * \tparam T3 \deduced Type of the third argument to the underlying function.
- * \param [in] mem_ptr Class method member function pointer
- * \param [in] obj Class instance.
- * \param [in] a1 First argument value to be bound to the underlying function.
- * \param [in] a2 Second argument value to be bound to the underlying function.
- * \param [in] a3 Third argument value to be bound to the underlying function.
- * \returns The constructed EventImpl.
- */
-template <typename MEM, typename OBJ, typename T1, typename T2, typename T3>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
-
-/**
- * \copybrief MakeEvent(MEM,OBJ)
- * \tparam MEM \deduced The class method function signature.
- * \tparam OBJ \deduced The class type holding the method.
- * \tparam T1 \deduced Type of the first argument to the underlying function.
- * \tparam T2 \deduced Type of the second argument to the underlying function.
- * \tparam T3 \deduced Type of the third argument to the underlying function.
- * \tparam T4 \deduced Type of the fourth argument to the underlying function.
- * \param [in] mem_ptr Class method member function pointer
- * \param [in] obj Class instance.
- * \param [in] a1 First argument value to be bound to the underlying function.
- * \param [in] a2 Second argument value to be bound to the underlying function.
- * \param [in] a3 Third argument value to be bound to the underlying function.
- * \param [in] a4 Fourth argument value to be bound to the underlying function.
- * \returns The constructed EventImpl.
- */
-template <typename MEM, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
-
-/**
- * \copybrief MakeEvent(MEM,OBJ)
- * \tparam MEM \deduced The class method function signature.
- * \tparam OBJ \deduced The class type holding the method.
- * \tparam T1 \deduced Type of the first argument to the underlying function.
- * \tparam T2 \deduced Type of the second argument to the underlying function.
- * \tparam T3 \deduced Type of the third argument to the underlying function.
- * \tparam T4 \deduced Type of the fourth argument to the underlying function.
- * \tparam T5 \deduced Type of the fifth argument to the underlying function.
- * \param [in] mem_ptr Class method member function pointer
- * \param [in] obj Class instance.
- * \param [in] a1 First argument value to be bound to the underlying function.
- * \param [in] a2 Second argument value to be bound to the underlying function.
- * \param [in] a3 Third argument value to be bound to the underlying function.
- * \param [in] a4 Fourth argument value to be bound to the underlying function.
- * \param [in] a5 Fifh argument value to be bound to the underlying function.
- * \returns The constructed EventImpl.
- */
-template <typename MEM,
-          typename OBJ,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
-
-/**
- * \copybrief MakeEvent(MEM,OBJ)
- * \tparam MEM The class method function signature.
- * \tparam OBJ The class type holding the method.
- * \tparam T1 Type of the first argument to the underlying function.
- * \tparam T2 Type of the second argument to the underlying function.
- * \tparam T3 Type of the third argument to the underlying function.
- * \tparam T4 Type of the fourth argument to the underlying function.
- * \tparam T5 Type of the fifth argument to the underlying function.
- * \tparam T6 Type of the sixth argument to the underlying function.
- * \param mem_ptr Class method member function pointer
- * \param obj Class instance.
- * \param a1 First argument value to be bound to the underlying function.
- * \param a2 Second argument value to be bound to the underlying function.
- * \param a3 Third argument value to be bound to the underlying function.
- * \param a4 Fourth argument value to be bound to the underlying function.
- * \param a5 Fifth argument value to be bound to the underlying function.
- * \param a6 Sixth argument value to be bound to the underlying function.
- * \returns The constructed EventImpl.
- */
-template <typename MEM,
-          typename OBJ,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5,
-          typename T6>
-EventImpl* MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);
-
-/**@}*/
+template <typename MEM, typename OBJ, typename... Ts>
+std::enable_if_t<std::is_member_pointer_v<MEM>, EventImpl*> MakeEvent(MEM mem_ptr,
+                                                                      OBJ obj,
+                                                                      Ts... args);
 
 /**
  * \ingroup events
@@ -190,148 +67,14 @@
  * Make an EventImpl from a function pointer taking varying numbers
  * of arguments.
  *
+ * \tparam Us \deduced Formal types of the arguments to the function.
+ * \tparam Ts \deduced Actual types of the arguments to the function.
  * \param [in] f The function pointer.
+ * \param [in] args Arguments to be bound to the function.
  * \returns The constructed EventImpl.
  */
-EventImpl* MakeEvent(void (*f)());
-
-/**
- * \copybrief MakeEvent(void(*f)())
- * \tparam U1 \deduced Formal type of the argument to the function.
- * \tparam T1 \deduced Actual type of the argument to the function.
- * \param [in] f The function pointer.
- * \param [in] a1 Argument to be bound to the function.
- * \returns The constructed EventImpl.
- */
-template <typename U1, typename T1>
-EventImpl* MakeEvent(void (*f)(U1), T1 a1);
-
-/**
- * \copybrief MakeEvent(void(*f)())
- * \tparam U1 \deduced Formal type of the first argument to the function.
- * \tparam U2 \deduced Formal type of the second argument to the function.
- * \tparam T1 \deduced Actual type of the first argument to the function.
- * \tparam T2 \deduced Actual type of the second argument to the function.
- * \param [in] f The function pointer.
- * \param [in] a1 First argument to be bound to the function.
- * \param [in] a2 Second argument to be bound to the function.
- * \returns The constructed EventImpl.
- */
-template <typename U1, typename U2, typename T1, typename T2>
-EventImpl* MakeEvent(void (*f)(U1, U2), T1 a1, T2 a2);
-
-/**
- * \copybrief MakeEvent(void(*f)())
- * \tparam U1 \deduced Formal type of the first argument to the function.
- * \tparam U2 \deduced Formal type of the second argument to the function.
- * \tparam U3 \deduced Formal type of the third argument to the function.
- * \tparam T1 \deduced Actual type of the first argument to the function.
- * \tparam T2 \deduced Actual type of the second argument to the function.
- * \tparam T3 \deduced Actual type of the third argument to the function.
- * \param [in] f The function pointer.
- * \param [in] a1 First argument to be bound to the function.
- * \param [in] a2 Second argument to be bound to the function.
- * \param [in] a3 Third argument to be bound to the function.
- * \returns The constructed EventImpl.
- */
-template <typename U1, typename U2, typename U3, typename T1, typename T2, typename T3>
-EventImpl* MakeEvent(void (*f)(U1, U2, U3), T1 a1, T2 a2, T3 a3);
-
-/**
- * \copybrief MakeEvent(void(*f)())
- * \tparam U1 \deduced Formal type of the first argument to the function.
- * \tparam U2 \deduced Formal type of the second argument to the function.
- * \tparam U3 \deduced Formal type of the third argument to the function.
- * \tparam U4 \deduced Formal type of the fourth argument to the function.
- * \tparam T1 \deduced Actual type of the first argument to the function.
- * \tparam T2 \deduced Actual type of the second argument to the function.
- * \tparam T3 \deduced Actual type of the third argument to the function.
- * \tparam T4 \deduced Actual type of the fourth argument to the function.
- * \param [in] f The function pointer.
- * \param [in] a1 First argument to be bound to the function.
- * \param [in] a2 Second argument to be bound to the function.
- * \param [in] a3 Third argument to be bound to the function.
- * \param [in] a4 Fourth argument to be bound to the function.
- * \returns The constructed EventImpl.
- */
-template <typename U1,
-          typename U2,
-          typename U3,
-          typename U4,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4>
-EventImpl* MakeEvent(void (*f)(U1, U2, U3, U4), T1 a1, T2 a2, T3 a3, T4 a4);
-
-/**
- * \copybrief MakeEvent(void(*f)())
- * \tparam U1 \deduced Formal type of the first argument to the function.
- * \tparam U2 \deduced Formal type of the second argument to the function.
- * \tparam U3 \deduced Formal type of the third argument to the function.
- * \tparam U4 \deduced Formal type of the fourth argument to the function.
- * \tparam U5 \deduced Formal type of the fifth argument to the function.
- * \tparam T1 \deduced Actual type of the first argument to the function.
- * \tparam T2 \deduced Actual type of the second argument to the function.
- * \tparam T3 \deduced Actual type of the third argument to the function.
- * \tparam T4 \deduced Actual type of the fourth argument to the function.
- * \tparam T5 \deduced Actual type of the fifth argument to the function.
- * \param [in] f The function pointer.
- * \param [in] a1 First argument to be bound to the function.
- * \param [in] a2 Second argument to be bound to the function.
- * \param [in] a3 Third argument to be bound to the function.
- * \param [in] a4 Fourth argument to be bound to the function.
- * \param [in] a5 Fifth argument to be bound to the function.
- * \returns The constructed EventImpl.
- */
-template <typename U1,
-          typename U2,
-          typename U3,
-          typename U4,
-          typename U5,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5>
-EventImpl* MakeEvent(void (*f)(U1, U2, U3, U4, U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
-
-/**
- * \copybrief MakeEvent(void(*f)())
- * \tparam U1 Formal type of the first argument to the function.
- * \tparam U2 Formal type of the second argument to the function.
- * \tparam U3 Formal type of the third argument to the function.
- * \tparam U4 Formal type of the fourth argument to the function.
- * \tparam U5 Formal type of the fifth argument to the function.
- * \tparam U6 Formal type of the sixth argument to the function.
- * \tparam T1 Actual type of the first argument to the function.
- * \tparam T2 Actual type of the second argument to the function.
- * \tparam T3 Actual type of the third argument to the function.
- * \tparam T4 Actual type of the fourth argument to the function.
- * \tparam T5 Actual type of the fifth argument to the function.
- * \tparam T6 Actual type of the sixth argument to the function.
- * \param f The function pointer.
- * \param a1 First argument to be bound to the function.
- * \param a2 Second argument to be bound to the function.
- * \param a3 Third argument to be bound to the function.
- * \param a4 Fourth argument to be bound to the function.
- * \param a5 Fifth argument to be bound to the function.
- * \param a6 Sixth argument to be bound to the function.
- * \returns The constructed EventImpl.
- */
-template <typename U1,
-          typename U2,
-          typename U3,
-          typename U4,
-          typename U5,
-          typename U6,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5,
-          typename T6>
-EventImpl* MakeEvent(void (*f)(U1, U2, U3, U4, U5, U6), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);
+template <typename... Us, typename... Ts>
+EventImpl* MakeEvent(void (*f)(Us...), Ts... args);
 
 /**
  * Make an EventImpl from a lambda.
@@ -351,13 +94,15 @@
  ********************************************************************/
 
 #include "event-impl.h"
-#include "type-traits.h"
 
 namespace ns3
 {
 
+namespace internal
+{
+
 /**
- * \ingroup makeeventmemptr
+ * \ingroup events
  * Helper for the MakeEvent functions which take a class method.
  *
  * This helper converts a pointer to a reference.
@@ -370,7 +115,7 @@
 struct EventMemberImplObjTraits;
 
 /**
- * \ingroup makeeventmemptr
+ * \ingroup events
  * Helper for the MakeEvent functions which take a class method.
  *
  * This helper converts a pointer to a reference.
@@ -392,544 +137,66 @@
     }
 };
 
-template <typename MEM, typename OBJ>
-EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj)
-{
-    // zero argument version
-    class EventMemberImpl0 : public EventImpl
-    {
-      public:
-        EventMemberImpl0(OBJ obj, MEM function)
-            : m_obj(obj),
-              m_function(function)
-        {
-        }
-
-        ~EventMemberImpl0() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*m_function)();
-        }
-
-        OBJ m_obj;
-        MEM m_function;
-    }* ev = new EventMemberImpl0(obj, mem_ptr);
-
-    return ev;
-}
+} // namespace internal
 
-template <typename MEM, typename OBJ, typename T1>
-EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj, T1 a1)
+template <typename MEM, typename OBJ, typename... Ts>
+std::enable_if_t<std::is_member_pointer_v<MEM>, EventImpl*>
+MakeEvent(MEM mem_ptr, OBJ obj, Ts... args)
 {
-    // one argument version
-    class EventMemberImpl1 : public EventImpl
+    class EventMemberImpl : public EventImpl
     {
       public:
-        EventMemberImpl1(OBJ obj, MEM function, T1 a1)
-            : m_obj(obj),
-              m_function(function),
-              m_a1(a1)
-        {
-        }
-
-      protected:
-        ~EventMemberImpl1() override
-        {
-        }
+        EventMemberImpl() = delete;
 
-      private:
-        void Notify() override
-        {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*m_function)(m_a1);
-        }
-
-        OBJ m_obj;
-        MEM m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-    }* ev = new EventMemberImpl1(obj, mem_ptr, a1);
-
-    return ev;
-}
-
-template <typename MEM, typename OBJ, typename T1, typename T2>
-EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
-{
-    // two argument version
-    class EventMemberImpl2 : public EventImpl
-    {
-      public:
-        EventMemberImpl2(OBJ obj, MEM function, T1 a1, T2 a2)
-            : m_obj(obj),
-              m_function(function),
-              m_a1(a1),
-              m_a2(a2)
+        EventMemberImpl(OBJ obj, MEM function, Ts... args)
+            : m_function(std::bind(function, obj, args...))
         {
         }
 
       protected:
-        ~EventMemberImpl2() override
+        ~EventMemberImpl() override
         {
         }
 
       private:
         void Notify() override
         {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*m_function)(m_a1, m_a2);
+            m_function();
         }
 
-        OBJ m_obj;
-        MEM m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-    }* ev = new EventMemberImpl2(obj, mem_ptr, a1, a2);
+        std::function<void()> m_function;
+    }* ev = new EventMemberImpl(obj, mem_ptr, args...);
 
     return ev;
 }
 
-template <typename MEM, typename OBJ, typename T1, typename T2, typename T3>
+template <typename... Us, typename... Ts>
 EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3)
+MakeEvent(void (*f)(Us...), Ts... args)
 {
-    // three argument version
-    class EventMemberImpl3 : public EventImpl
+    class EventFunctionImpl : public EventImpl
     {
       public:
-        EventMemberImpl3(OBJ obj, MEM function, T1 a1, T2 a2, T3 a3)
-            : m_obj(obj),
-              m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3)
-        {
-        }
-
-      protected:
-        ~EventMemberImpl3() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*m_function)(m_a1, m_a2, m_a3);
-        }
-
-        OBJ m_obj;
-        MEM m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-    }* ev = new EventMemberImpl3(obj, mem_ptr, a1, a2, a3);
-
-    return ev;
-}
-
-template <typename MEM, typename OBJ, typename T1, typename T2, typename T3, typename T4>
-EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
-{
-    // four argument version
-    class EventMemberImpl4 : public EventImpl
-    {
-      public:
-        EventMemberImpl4(OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4)
-            : m_obj(obj),
-              m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3),
-              m_a4(a4)
-        {
-        }
-
-      protected:
-        ~EventMemberImpl4() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*
-             m_function)(m_a1, m_a2, m_a3, m_a4);
-        }
-
-        OBJ m_obj;
-        MEM m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-        typename TypeTraits<T4>::ReferencedType m_a4;
-    }* ev = new EventMemberImpl4(obj, mem_ptr, a1, a2, a3, a4);
-
-    return ev;
-}
-
-template <typename MEM,
-          typename OBJ,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5>
-EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
-{
-    // five argument version
-    class EventMemberImpl5 : public EventImpl
-    {
-      public:
-        EventMemberImpl5(OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
-            : m_obj(obj),
-              m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3),
-              m_a4(a4),
-              m_a5(a5)
-        {
-        }
-
-      protected:
-        ~EventMemberImpl5() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*
-             m_function)(m_a1, m_a2, m_a3, m_a4, m_a5);
-        }
-
-        OBJ m_obj;
-        MEM m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-        typename TypeTraits<T4>::ReferencedType m_a4;
-        typename TypeTraits<T5>::ReferencedType m_a5;
-    }* ev = new EventMemberImpl5(obj, mem_ptr, a1, a2, a3, a4, a5);
-
-    return ev;
-}
-
-template <typename MEM,
-          typename OBJ,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5,
-          typename T6>
-EventImpl*
-MakeEvent(MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
-{
-    // six argument version
-    class EventMemberImpl6 : public EventImpl
-    {
-      public:
-        EventMemberImpl6(OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
-            : m_obj(obj),
-              m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3),
-              m_a4(a4),
-              m_a5(a5),
-              m_a6(a6)
-        {
-        }
-
-      protected:
-        ~EventMemberImpl6() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (EventMemberImplObjTraits<OBJ>::GetReference(m_obj).*
-             m_function)(m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
-        }
-
-        OBJ m_obj;
-        MEM m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-        typename TypeTraits<T4>::ReferencedType m_a4;
-        typename TypeTraits<T5>::ReferencedType m_a5;
-        typename TypeTraits<T6>::ReferencedType m_a6;
-    }* ev = new EventMemberImpl6(obj, mem_ptr, a1, a2, a3, a4, a5, a6);
-
-    return ev;
-}
-
-template <typename U1, typename T1>
-EventImpl*
-MakeEvent(void (*f)(U1), T1 a1)
-{
-    // one arg version
-    class EventFunctionImpl1 : public EventImpl
-    {
-      public:
-        [[maybe_unused]] typedef void (*F)(U1);
-
-        EventFunctionImpl1(F function, T1 a1)
-            : m_function(function),
-              m_a1(a1)
-        {
-        }
-
-      protected:
-        ~EventFunctionImpl1() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (*m_function)(m_a1);
-        }
-
-        F m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-    }* ev = new EventFunctionImpl1(f, a1);
-
-    return ev;
-}
-
-template <typename U1, typename U2, typename T1, typename T2>
-EventImpl*
-MakeEvent(void (*f)(U1, U2), T1 a1, T2 a2)
-{
-    // two arg version
-    class EventFunctionImpl2 : public EventImpl
-    {
-      public:
-        [[maybe_unused]] typedef void (*F)(U1, U2);
-
-        EventFunctionImpl2(F function, T1 a1, T2 a2)
-            : m_function(function),
-              m_a1(a1),
-              m_a2(a2)
-        {
-        }
-
-      protected:
-        ~EventFunctionImpl2() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (*m_function)(m_a1, m_a2);
-        }
-
-        F m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-    }* ev = new EventFunctionImpl2(f, a1, a2);
-
-    return ev;
-}
-
-template <typename U1, typename U2, typename U3, typename T1, typename T2, typename T3>
-EventImpl*
-MakeEvent(void (*f)(U1, U2, U3), T1 a1, T2 a2, T3 a3)
-{
-    // three arg version
-    class EventFunctionImpl3 : public EventImpl
-    {
-      public:
-        [[maybe_unused]] typedef void (*F)(U1, U2, U3);
-
-        EventFunctionImpl3(F function, T1 a1, T2 a2, T3 a3)
-            : m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3)
-        {
-        }
-
-      protected:
-        ~EventFunctionImpl3() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (*m_function)(m_a1, m_a2, m_a3);
-        }
-
-        F m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-    }* ev = new EventFunctionImpl3(f, a1, a2, a3);
-
-    return ev;
-}
-
-template <typename U1,
-          typename U2,
-          typename U3,
-          typename U4,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4>
-EventImpl*
-MakeEvent(void (*f)(U1, U2, U3, U4), T1 a1, T2 a2, T3 a3, T4 a4)
-{
-    // four arg version
-    class EventFunctionImpl4 : public EventImpl
-    {
-      public:
-        [[maybe_unused]] typedef void (*F)(U1, U2, U3, U4);
-
-        EventFunctionImpl4(F function, T1 a1, T2 a2, T3 a3, T4 a4)
-            : m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3),
-              m_a4(a4)
-        {
-        }
-
-      protected:
-        ~EventFunctionImpl4() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (*m_function)(m_a1, m_a2, m_a3, m_a4);
-        }
-
-        F m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-        typename TypeTraits<T4>::ReferencedType m_a4;
-    }* ev = new EventFunctionImpl4(f, a1, a2, a3, a4);
-
-    return ev;
-}
-
-template <typename U1,
-          typename U2,
-          typename U3,
-          typename U4,
-          typename U5,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5>
-EventImpl*
-MakeEvent(void (*f)(U1, U2, U3, U4, U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
-{
-    // five arg version
-    class EventFunctionImpl5 : public EventImpl
-    {
-      public:
-        [[maybe_unused]] typedef void (*F)(U1, U2, U3, U4, U5);
-
-        EventFunctionImpl5(F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
-            : m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3),
-              m_a4(a4),
-              m_a5(a5)
-        {
-        }
-
-      protected:
-        ~EventFunctionImpl5() override
-        {
-        }
-
-      private:
-        void Notify() override
-        {
-            (*m_function)(m_a1, m_a2, m_a3, m_a4, m_a5);
-        }
-
-        F m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-        typename TypeTraits<T4>::ReferencedType m_a4;
-        typename TypeTraits<T5>::ReferencedType m_a5;
-    }* ev = new EventFunctionImpl5(f, a1, a2, a3, a4, a5);
-
-    return ev;
-}
-
-template <typename U1,
-          typename U2,
-          typename U3,
-          typename U4,
-          typename U5,
-          typename U6,
-          typename T1,
-          typename T2,
-          typename T3,
-          typename T4,
-          typename T5,
-          typename T6>
-EventImpl*
-MakeEvent(void (*f)(U1, U2, U3, U4, U5, U6), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
-{
-    // six arg version
-    class EventFunctionImpl6 : public EventImpl
-    {
-      public:
-        [[maybe_unused]] typedef void (*F)(U1, U2, U3, U4, U5, U6);
-
-        EventFunctionImpl6(F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
+        EventFunctionImpl(void (*function)(Us...), Ts... args)
             : m_function(function),
-              m_a1(a1),
-              m_a2(a2),
-              m_a3(a3),
-              m_a4(a4),
-              m_a5(a5),
-              m_a6(a6)
+              m_arguments(args...)
         {
         }
 
       protected:
-        ~EventFunctionImpl6() override
+        ~EventFunctionImpl() override
         {
         }
 
       private:
         void Notify() override
         {
-            (*m_function)(m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
+            std::apply([this](Ts... args) { (*m_function)(args...); }, m_arguments);
         }
 
-        F m_function;
-        typename TypeTraits<T1>::ReferencedType m_a1;
-        typename TypeTraits<T2>::ReferencedType m_a2;
-        typename TypeTraits<T3>::ReferencedType m_a3;
-        typename TypeTraits<T4>::ReferencedType m_a4;
-        typename TypeTraits<T5>::ReferencedType m_a5;
-        typename TypeTraits<T6>::ReferencedType m_a6;
-    }* ev = new EventFunctionImpl6(f, a1, a2, a3, a4, a5, a6);
+        void (*m_function)(Us...);
+        std::tuple<std::remove_reference_t<Ts>...> m_arguments;
+    }* ev = new EventFunctionImpl(f, args...);
 
     return ev;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/matrix-array.cc ns-3.42/src/core/model/matrix-array.cc
--- ns-3.41/src/core/model/matrix-array.cc	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/matrix-array.cc	2024-05-29 15:29:46.932073000 -0700
@@ -158,6 +158,70 @@
 
 template <class T>
 MatrixArray<T>
+MatrixArray<T>::Determinant() const
+{
+    MatrixArray<T> res{1, 1, m_numPages};
+    NS_ASSERT_MSG(m_numRows == m_numCols, "Matrix is not square");
+    // In case of small matrices, we use a fast path
+    if (m_numRows == 1)
+    {
+        return *this;
+    }
+    // Calculate determinant for each matrix
+    for (size_t page = 0; page < m_numPages; ++page)
+    {
+        res(0, 0, page) = 0;
+        auto pageValues = GetPagePtr(page);
+
+        // Fast path for 2x2 matrices
+        if (m_numRows == 2)
+        {
+            res(0, 0, page) = pageValues[0] * pageValues[3] - pageValues[1] * pageValues[2];
+            continue;
+        }
+        for (size_t detN = 0; detN < m_numRows; detN++)
+        {
+            auto partDetP = T{0} + 1.0;
+            auto partDetN = T{0} + 1.0;
+            for (size_t row = 0; row < m_numRows; row++)
+            {
+                // Wraparound not to have to extend the matrix
+                // Positive determinant
+                size_t col = (row + detN) % m_numCols;
+                partDetP *= pageValues[row * m_numCols + col];
+
+                // Negative determinant
+                col = m_numCols - 1 - (row + detN) % m_numCols;
+                partDetN *= pageValues[row * m_numCols + col];
+            }
+            res(0, 0, page) += partDetP - partDetN;
+        }
+    }
+    return res;
+}
+
+template <class T>
+MatrixArray<T>
+MatrixArray<T>::FrobeniusNorm() const
+{
+    MatrixArray<T> res{1, 1, m_numPages};
+    for (size_t page = 0; page < m_numPages; ++page)
+    {
+        // Calculate the sum of squared absolute values of each matrix page
+        res[page] = 0;
+        auto pagePtr = this->GetPagePtr(page);
+        for (size_t i = 0; i < m_numRows * m_numCols; i++)
+        {
+            auto absVal = std::abs(pagePtr[i]);
+            res[page] += absVal * absVal;
+        }
+        res[page] = sqrt(res[page]);
+    }
+    return res;
+}
+
+template <class T>
+MatrixArray<T>
 MatrixArray<T>::MultiplyByLeftAndRightMatrix(const MatrixArray<T>& lMatrix,
                                              const MatrixArray<T>& rMatrix) const
 {
@@ -229,6 +293,84 @@
     return retMatrix;
 }
 
+template <class T>
+MatrixArray<T>
+MatrixArray<T>::MakeNCopies(size_t nCopies) const
+{
+    NS_ASSERT_MSG(m_numPages == 1, "The MatrixArray should have only one page to be copied.");
+    auto copiedMatrix = MatrixArray<T>{m_numRows, m_numCols, nCopies};
+    for (size_t copy = 0; copy < nCopies; copy++)
+    {
+        for (size_t i = 0; i < m_numRows * m_numCols; i++)
+        {
+            copiedMatrix.GetPagePtr(copy)[i] = m_values[i];
+        }
+    }
+    return copiedMatrix;
+}
+
+template <class T>
+MatrixArray<T>
+MatrixArray<T>::ExtractPage(size_t page) const
+{
+    NS_ASSERT_MSG(page < m_numPages, "The page to extract from the MatrixArray is out of bounds.");
+    auto extractedPage = MatrixArray<T>{m_numRows, m_numCols, 1};
+
+    for (size_t i = 0; i < m_numRows * m_numCols; ++i)
+    {
+        extractedPage.m_values[i] = GetPagePtr(page)[i];
+    }
+    return extractedPage;
+}
+
+template <class T>
+MatrixArray<T>
+MatrixArray<T>::JoinPages(const std::vector<MatrixArray<T>>& pages)
+{
+    auto jointMatrix =
+        MatrixArray<T>{pages.front().GetNumRows(), pages.front().GetNumCols(), pages.size()};
+    for (size_t page = 0; page < jointMatrix.GetNumPages(); page++)
+    {
+        NS_ASSERT_MSG(pages[page].GetNumRows() == jointMatrix.GetNumRows(),
+                      "All page matrices should have the same number of rows");
+        NS_ASSERT_MSG(pages[page].GetNumCols() == jointMatrix.GetNumCols(),
+                      "All page matrices should have the same number of columns");
+        NS_ASSERT_MSG(pages[page].GetNumPages() == 1,
+                      "All page matrices should have a single page");
+
+        size_t i = 0;
+        for (auto a : pages[page].GetValues())
+        {
+            jointMatrix.GetPagePtr(page)[i] = a;
+            i++;
+        }
+    }
+    return jointMatrix;
+}
+
+template <class T>
+MatrixArray<T>
+MatrixArray<T>::IdentityMatrix(const size_t size, const size_t pages)
+{
+    auto identityMatrix = MatrixArray<T>{size, size, pages};
+    for (std::size_t page = 0; page < pages; page++)
+    {
+        for (std::size_t i = 0; i < size; i++)
+        {
+            identityMatrix(i, i, page) = 1.0;
+        }
+    }
+    return identityMatrix;
+}
+
+template <class T>
+MatrixArray<T>
+MatrixArray<T>::IdentityMatrix(const MatrixArray& likeme)
+{
+    NS_ASSERT_MSG(likeme.GetNumRows() == likeme.GetNumCols(), "Template array is not square.");
+    return IdentityMatrix(likeme.GetNumRows(), likeme.GetNumPages());
+}
+
 template MatrixArray<std::complex<double>> MatrixArray<std::complex<double>>::HermitianTranspose()
     const;
 template class MatrixArray<std::complex<double>>;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/matrix-array.h ns-3.42/src/core/model/matrix-array.h
--- ns-3.41/src/core/model/matrix-array.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/matrix-array.h	2024-05-29 15:29:46.932073000 -0700
@@ -190,6 +190,16 @@
      */
     MatrixArray Transpose() const;
     /**
+     * \brief This operator calculates a vector o determinants, one for each page
+     * \return The resulting MatrixArray with the determinants for each page.
+     */
+    MatrixArray Determinant() const;
+    /**
+     * \brief This operator calculates a vector of Frobenius norm, one for each page
+     * \return The resulting MatrixArray with the Frobenius norm for each page.
+     */
+    MatrixArray FrobeniusNorm() const;
+    /**
      *\brief Multiply each matrix in the array by the left and the right matrix.
      * For each page of this MatrixArray the operation performed is
      * lMatrix * matrix(pageIndex) * rMatrix, and the resulting MatrixArray<T>
@@ -229,6 +239,40 @@
               typename = std::enable_if_t<(std::is_same_v<T, std::complex<double>> && EnableBool)>>
     MatrixArray<T> HermitianTranspose() const;
 
+    /**
+     * \brief Function that copies the current 1-page matrix into a new matrix with n copies of the
+     * original matrix
+     * \param nCopies Number of copies to make of the input 1-page MatrixArray
+     * \return Returns a new matrix with n page copies
+     */
+    MatrixArray<T> MakeNCopies(size_t nCopies) const;
+    /**
+     * \brief Function extracts a page from a MatrixArray
+     * \param page Index of the page to be extracted from the n-page MatrixArray
+     * \return Returns an extracted page of the original MatrixArray
+     */
+    MatrixArray<T> ExtractPage(size_t page) const;
+    /**
+     * \brief Function joins multiple pages into a single MatrixArray
+     * \param pages Vector containing n 1-page MatrixArrays to be merged into a n-page MatrixArray
+     * \return Returns a joint MatrixArray
+     */
+    static MatrixArray<T> JoinPages(const std::vector<MatrixArray<T>>& pages);
+    /**
+     * \brief Function produces an identity MatrixArray with the specified size
+     * \param size Size of the output identity matrix
+     * \param pages Number of copies of the identity matrix
+     * \return Returns an identity MatrixArray
+     */
+    static MatrixArray<T> IdentityMatrix(const size_t size, const size_t pages = 1);
+    /**
+     * \brief Function produces an identity MatrixArray with the same size
+     * as the input MatrixArray
+     * \param likeme Input matrix used to determine the size of the identity matrix
+     * \return Returns an identity MatrixArray
+     */
+    static MatrixArray<T> IdentityMatrix(const MatrixArray& likeme);
+
   protected:
     // To simplify functions in MatrixArray that are using members from the template base class
     using ValArray<T>::m_numRows;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/nstime.h ns-3.42/src/core/model/nstime.h
--- ns-3.41/src/core/model/nstime.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/nstime.h	2024-05-29 15:29:46.932073000 -0700
@@ -841,13 +841,6 @@
 } // namespace TracedValueCallback
 
 /**
- * Force static initialization order of Time in each compilation unit.
- * This is internal to the Time implementation.
- * \relates Time
- */
-static bool g_TimeStaticInit [[maybe_unused]] = Time::StaticInit();
-
-/**
  * Equality operator for Time.
  * \param [in] lhs The first value
  * \param [in] rhs The second value
@@ -1414,9 +1407,9 @@
 ATTRIBUTE_ACCESSOR_DEFINE(Time);
 
 /**
- *  \ingroup attribute_time
- *  Helper to make a Time checker with bounded range.
- *  Both limits are inclusive
+ * \ingroup attribute_Time
+ * Helper to make a Time checker with bounded range.
+ * Both limits are inclusive
  *
  * \param [in] min Minimum allowed value.
  * \param [in] max Maximum allowed value.
@@ -1425,7 +1418,7 @@
 Ptr<const AttributeChecker> MakeTimeChecker(const Time min, const Time max);
 
 /**
- * \ingroup attribute_time
+ * \ingroup attribute_Time
  * Helper to make an unbounded Time checker.
  *
  * \return The AttributeChecker
@@ -1437,7 +1430,7 @@
 }
 
 /**
- * \ingroup attribute_time
+ * \ingroup attribute_Time
  * Helper to make a Time checker with a lower bound.
  *
  * \param [in] min Minimum allowed value.
@@ -1490,6 +1483,27 @@
  */
 TYPENAMEGET_DEFINE(Time);
 
+/**
+ * \ingroup time
+ *
+ * \brief Helper class to force static initialization
+ * of Time in each compilation unit, ensuring it is
+ * initialized before usage.
+ * This is internal to the Time implementation.
+ * \relates Time
+ */
+class TimeInitializationHelper
+{
+  public:
+    /** Default constructor calls Time::StaticInit */
+    TimeInitializationHelper()
+    {
+        Time::StaticInit();
+    }
+};
+
+static TimeInitializationHelper g_timeInitHelper; ///< Instance of Time static initialization helper
+
 } // namespace ns3
 
 #endif /* TIME_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/object-base.cc ns-3.42/src/core/model/object-base.cc
--- ns-3.41/src/core/model/object-base.cc	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/object-base.cc	2024-05-29 15:29:46.932073000 -0700
@@ -36,6 +36,13 @@
 namespace ns3
 {
 // Explicit instantiation declaration
+
+/**
+ * \ingroup callback
+ * Explicit instantiation for ObjectBase
+ * \return A wrapper Callback
+ * \sa ns3::MakeCallback
+ */
 template Callback<ObjectBase*> MakeCallback<ObjectBase*>(ObjectBase* (*)());
 template Callback<ObjectBase*>::Callback();
 template class CallbackImpl<ObjectBase*>;
@@ -319,6 +326,7 @@
     Ptr<const TraceSourceAccessor> accessor = tid.LookupTraceSourceByName(name);
     if (!accessor)
     {
+        NS_LOG_DEBUG("Cannot connect trace " << name << " on object of type " << tid.GetName());
         return false;
     }
     bool ok = accessor->ConnectWithoutContext(this, cb);
@@ -333,6 +341,7 @@
     Ptr<const TraceSourceAccessor> accessor = tid.LookupTraceSourceByName(name);
     if (!accessor)
     {
+        NS_LOG_DEBUG("Cannot connect trace " << name << " on object of type " << tid.GetName());
         return false;
     }
     bool ok = accessor->Connect(this, context, cb);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/object.cc ns-3.42/src/core/model/object.cc
--- ns-3.41/src/core/model/object.cc	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/object.cc	2024-05-29 15:29:46.932073000 -0700
@@ -59,16 +59,27 @@
 Object::AggregateIterator::HasNext() const
 {
     NS_LOG_FUNCTION(this);
-    return m_current < m_object->m_aggregates->n;
+    return (m_current < m_object->m_aggregates->n) ||
+           (m_uniAggrIter != m_object->m_unidirectionalAggregates.end());
 }
 
 Ptr<const Object>
 Object::AggregateIterator::Next()
 {
     NS_LOG_FUNCTION(this);
-    Object* object = m_object->m_aggregates->buffer[m_current];
-    m_current++;
-    return object;
+    if (m_current < m_object->m_aggregates->n)
+    {
+        Object* object = m_object->m_aggregates->buffer[m_current];
+        m_current++;
+        return object;
+    }
+    else if (m_uniAggrIter != m_object->m_unidirectionalAggregates.end())
+    {
+        auto object = *m_uniAggrIter;
+        m_uniAggrIter++;
+        return object;
+    }
+    return nullptr;
 }
 
 Object::AggregateIterator::AggregateIterator(Ptr<const Object> object)
@@ -76,6 +87,7 @@
       m_current(0)
 {
     NS_LOG_FUNCTION(this << object);
+    m_uniAggrIter = object->m_unidirectionalAggregates.begin();
 }
 
 TypeId
@@ -127,6 +139,7 @@
         std::free(m_aggregates);
     }
     m_aggregates = nullptr;
+    m_unidirectionalAggregates.clear();
 }
 
 Object::Object(const Object& o)
@@ -153,6 +166,7 @@
     NS_LOG_FUNCTION(this << tid);
     NS_ASSERT(CheckLoose());
 
+    // First check if the object is in the normal aggregates.
     uint32_t n = m_aggregates->n;
     TypeId objectTid = Object::GetTypeId();
     for (uint32_t i = 0; i < n; i++)
@@ -179,6 +193,20 @@
             return const_cast<Object*>(current);
         }
     }
+
+    // Next check if it's a unidirectional aggregate
+    for (auto& uniItem : m_unidirectionalAggregates)
+    {
+        TypeId cur = uniItem->GetInstanceTypeId();
+        while (cur != tid && cur != objectTid)
+        {
+            cur = cur.GetParent();
+        }
+        if (cur == tid)
+        {
+            return uniItem;
+        }
+    }
     return nullptr;
 }
 
@@ -206,6 +234,17 @@
             goto restart;
         }
     }
+
+    // note: no need to restart because unidirectionally aggregated objects
+    // can not change the status of the actual object.
+    for (auto& uniItem : m_unidirectionalAggregates)
+    {
+        if (!uniItem->m_initialized)
+        {
+            uniItem->DoInitialize();
+            uniItem->m_initialized = true;
+        }
+    }
 }
 
 bool
@@ -239,6 +278,17 @@
             goto restart;
         }
     }
+
+    // note: no need to restart because unidirectionally aggregated objects
+    // can not change the status of the actual object.
+    for (auto& uniItem : m_unidirectionalAggregates)
+    {
+        if (!uniItem->m_disposed && uniItem->GetReferenceCount() == 1)
+        {
+            uniItem->DoDispose();
+            uniItem->m_disposed = true;
+        }
+    }
 }
 
 void
@@ -280,11 +330,13 @@
     {
         aggregates->buffer[m_aggregates->n + i] = other->m_aggregates->buffer[i];
         const TypeId typeId = other->m_aggregates->buffer[i]->GetInstanceTypeId();
+        // note: DoGetObject scans also the unidirectional aggregates
         if (DoGetObject(typeId))
         {
             NS_FATAL_ERROR("Object::AggregateObject(): "
                            "Multiple aggregation of objects of type "
-                           << other->GetInstanceTypeId() << " on objects of type " << typeId);
+                           << other->GetInstanceTypeId() << " on objects of type "
+                           << GetInstanceTypeId());
         }
         UpdateSortedArray(aggregates, m_aggregates->n + i);
     }
@@ -323,7 +375,47 @@
     std::free(b);
 }
 
-/**
+void
+Object::UnidirectionalAggregateObject(Ptr<Object> o)
+{
+    NS_LOG_FUNCTION(this << o);
+    NS_ASSERT(!m_disposed);
+    NS_ASSERT(!o->m_disposed);
+    NS_ASSERT(CheckLoose());
+    NS_ASSERT(o->CheckLoose());
+
+    Object* other = PeekPointer(o);
+
+    const TypeId typeId = other->GetInstanceTypeId();
+    // note: DoGetObject scans also the unidirectional aggregates
+    if (DoGetObject(typeId))
+    {
+        NS_FATAL_ERROR("Object::UnidirectionalAggregateObject(): "
+                       "Multiple aggregation of objects of type "
+                       << other->GetInstanceTypeId() << " on objects of type "
+                       << GetInstanceTypeId());
+    }
+
+    m_unidirectionalAggregates.emplace_back(other);
+
+    // Finally, call NotifyNewAggregate on all the objects aggregates by this object.
+    // We skip the aggregated Object and its aggregates because they are not
+    // mutually aggregated to the others.
+    // Unfortunately, we have to make a copy of the aggregated objects, because
+    // NotifyNewAggregate might change it...
+
+    std::list<Object*> aggregates;
+    for (uint32_t i = 0; i < m_aggregates->n; i++)
+    {
+        aggregates.emplace_back(m_aggregates->buffer[i]);
+    }
+    for (auto& item : aggregates)
+    {
+        item->NotifyNewAggregate();
+    }
+}
+
+/*
  * This function must be implemented in the stack that needs to notify
  * other stacks connected to the node of their presence in the node.
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/object-factory.cc ns-3.42/src/core/model/object-factory.cc
--- ns-3.41/src/core/model/object-factory.cc	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/object-factory.cc	2024-05-29 15:29:46.932073000 -0700
@@ -93,6 +93,9 @@
 ObjectFactory::Create() const
 {
     NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(
+        m_tid.GetUid(),
+        "ObjectFactory::Create - can't use an ObjectFactory without setting a TypeId first.");
     Callback<ObjectBase*> cb = m_tid.GetConstructor();
     ObjectBase* base = cb();
     auto derived = dynamic_cast<Object*>(base);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/object-factory.h ns-3.42/src/core/model/object-factory.h
--- ns-3.41/src/core/model/object-factory.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/object-factory.h	2024-05-29 15:29:46.932073000 -0700
@@ -205,7 +205,11 @@
 ObjectFactory::Create() const
 {
     Ptr<Object> object = Create();
-    return object->GetObject<T>();
+    auto obj = object->GetObject<T>();
+    NS_ASSERT_MSG(obj != nullptr,
+                  "ObjectFactory::Create error: incompatible types ("
+                      << T::GetTypeId().GetName() << " and " << object->GetInstanceTypeId() << ")");
+    return obj;
 }
 
 template <typename... Args>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/object.h ns-3.42/src/core/model/object.h
--- ns-3.41/src/core/model/object.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/object.h	2024-05-29 15:29:46.932073000 -0700
@@ -137,6 +137,8 @@
         AggregateIterator(Ptr<const Object> object);
         Ptr<const Object> m_object; //!< Parent Object.
         uint32_t m_current;         //!< Current position in parent's aggregates.
+        /// Iterator to the unidirectional aggregates.
+        std::vector<Ptr<Object>>::const_iterator m_uniAggrIter;
     };
 
     /** Constructor. */
@@ -200,6 +202,44 @@
     void AggregateObject(Ptr<Object> other);
 
     /**
+     * Aggregate an Object to another Object.
+     *
+     * \param [in] other The other Object pointer
+     *
+     * This method aggregates the an object to another Object:
+     * after this method returns, it becomes possible to call GetObject()
+     * on the aggregating Object to get the other, but not vice-versa.
+     *
+     * This method calls the virtual method NotifyNewAggregates() to
+     * notify all aggregated Objects that they have been aggregated
+     * together.
+     *
+     * This method is useful only if there is the need to aggregate an
+     * object to more than one object at the same time, and should be avoided
+     * if not strictly necessary.
+     * In particular, objects aggregated with this method should be destroyed
+     * only after making sure that the objects they are aggregated to are
+     * destroyed as well. However, the destruction of the aggregating objects
+     * will take care of the unidirectional aggregated objects gracefully.
+     *
+     * Beware that an object aggregated to another with this function
+     * behaves differently than other aggregates in the following ways.
+     * Suppose that Object B is aggregated unidirectionally:
+     *   - It can be aggregated unidirectionally to more than one objects
+     *     (e.g., A1 and A2).
+     *   - It is not possible to call GetObject on B to find an aggregate of
+     *     object A1 or A2.
+     *   - When A1 or A2 are initialized, B is initialized, whichever happens first.
+     *   - When A1 or A2 are destroyed, B is destroyed, whichever happens last.
+     *   - If B is initialized, A1 and A2 are unaffected.
+     *   - If B is forcefully destroyed, A1 and A2 are unaffected.
+     *
+     *
+     * \sa AggregateObject()
+     */
+    void UnidirectionalAggregateObject(Ptr<Object> other);
+
+    /**
      * Get an iterator to the Objects aggregated to this one.
      *
      * \returns An iterator to the first Object aggregated to this
@@ -436,6 +476,17 @@
      * so the size of the array is indirectly a reference count.
      */
     Aggregates* m_aggregates;
+
+    /**
+     * An array of unidirectional aggregates, i.e., objects that are
+     * aggregated to the current object, but not vice-versa.
+     *
+     * This is useful (and suggested) only for Objects that should
+     * be aggregated to multiple other Objects, where the normal
+     * Aggregation would create an issue.
+     */
+    std::vector<Ptr<Object>> m_unidirectionalAggregates;
+
     /**
      * The number of times the Object was accessed with a
      * call to GetObject().
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/object-ptr-container.h ns-3.42/src/core/model/object-ptr-container.h
--- ns-3.41/src/core/model/object-ptr-container.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/object-ptr-container.h	2024-05-29 15:29:46.932073000 -0700
@@ -31,6 +31,11 @@
  * ns3::ObjectPtrContainerValue attribute value declarations and template implementations.
  */
 
+/**
+ * \ingroup attributes
+ * \defgroup attribute_ObjectPtrContainer ObjectPtrContainer Attribute
+ * AttributeValue implementation for ObjectPtrContainer
+ */
 namespace ns3
 {
 
@@ -41,6 +46,12 @@
  *
  * This class it used to get attribute access to an array of
  * ns3::Object pointers.
+ *
+ * \see AttributeValue
+ *
+ * Call graph was not generated because of its size.
+ * \hidecallergraph
+ * \hidecallgraph
  */
 class ObjectPtrContainerValue : public AttributeValue
 {
@@ -146,6 +157,12 @@
 Ptr<const AttributeAccessor> MakeObjectPtrContainerAccessor(INDEX (T::*getN)() const,
                                                             Ptr<U> (T::*get)(INDEX) const);
 
+/**
+ * \ingroup attribute_ObjectPtrContainer
+ *
+ * AttributeChecker implementation for ObjectPtrContainerValue.
+ * \see AttributeChecker
+ */
 class ObjectPtrContainerChecker : public AttributeChecker
 {
   public:
@@ -156,22 +173,28 @@
     virtual TypeId GetItemTypeId() const = 0;
 };
 
+/**
+ * \ingroup attribute_ObjectPtrContainer
+ * \returns The AttributeChecker.
+ * \see AttributeChecker
+ */
 template <typename T>
 Ptr<const AttributeChecker> MakeObjectPtrContainerChecker();
 
 } // namespace ns3
 
-/***************************************************************
- *        The implementation of the above functions.
- ***************************************************************/
+//
+// The implementation of the above functions.
+//
 
 namespace ns3
 {
 
 namespace internal
 {
-
-/** ObjectPtrContainerChecker implementation class. */
+/**
+ * ObjectPtrContainerChecker implementation class.
+ */
 template <typename T>
 class ObjectPtrContainerChecker : public ns3::ObjectPtrContainerChecker
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/pair.h ns-3.42/src/core/model/pair.h
--- ns-3.41/src/core/model/pair.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/pair.h	2024-05-29 15:29:46.932073000 -0700
@@ -47,10 +47,19 @@
     return os;
 }
 
-// Doxygen for this class is auto-generated by
-// utils/print-introspected-doxygen.h
+/**
+ * \ingroup attributes
+ * \defgroup attribute_Pair Pair Attribute
+ * AttributeValue implementation for Pair
+ */
 
-/** Hold objects of type std::pair<A, B>. */
+/**
+ * \ingroup attribute_Pair
+ * AttributeValue implementation for Pair.
+ * Hold objects of type std::pair<A, B>.
+ *
+ * \see AttributeValue
+ */
 template <class A, class B>
 class PairValue : public AttributeValue
 {
@@ -64,14 +73,18 @@
     /** Type returned by Get or passed in Set. */
     typedef typename std::pair<first_type, second_type> result_type;
 
-    PairValue();
+    PairValue()
+        : m_value(std::make_pair(Create<A>(), Create<B>())){};
 
     /**
      * Construct this PairValue from a std::pair
      *
      * \param [in] value Value with which to construct.
      */
-    PairValue(const result_type& value); // "import" constructor
+    PairValue(const result_type& value)
+    {
+        Set(value);
+    }; // "import" constructor
 
     // Inherited
     Ptr<AttributeValue> Copy() const override;
@@ -86,16 +99,30 @@
      * \return stored value as std::pair<A, B>.
      */
     result_type Get() const;
-    /* Documented by print-introspected-doxygen.cc */
+    /**
+     * Set the value.
+     * \param [in] value The value to adopt.
+     */
     void Set(const result_type& value);
 
+    /**
+     * Access the Pair value as type \p T.
+     * \tparam T \explicit The type to cast to.
+     * \param [out] value The Pair value, as type \p T.
+     * \returns true.
+     */
     template <typename T>
     bool GetAccessor(T& value) const;
 
   private:
-    value_type m_value;
+    value_type m_value; //!< The stored Pair instance.
 };
 
+/**
+ * \ingroup attribute_Pair
+ * AttributeChecker implementation for PairValue.
+ * \see AttributeChecker
+ */
 class PairChecker : public AttributeChecker
 {
   public:
@@ -120,6 +147,8 @@
 };
 
 /**
+ * \ingroup attribute_Pair
+ *
  * Make a PairChecker from a PairValue.
  *
  * This function returns a Pointer to a non-const instance to
@@ -131,6 +160,8 @@
 Ptr<AttributeChecker> MakePairChecker(const PairValue<A, B>& value);
 
 /**
+ * \ingroup attribute_Pair
+ *
  * Make a PairChecker from abscissa and ordinate AttributeCheckers.
  *
  * This function returns a Pointer to a const instance since both
@@ -145,6 +176,8 @@
                                             Ptr<const AttributeChecker> secondchecker);
 
 /**
+ * \ingroup attribute_Pair
+ *
  * Make a PairChecker without abscissa and ordinate AttributeCheckers.
  *
  * \return Pointer to PairChecker instance.
@@ -152,6 +185,16 @@
 template <class A, class B>
 Ptr<AttributeChecker> MakePairChecker();
 
+/**
+ * \ingroup attribute_Pair
+ *
+ * Create an AttributeAccessor for std::pair<>.
+ * \tparam A \explicit The type of pair.first.
+ * \tparam B \explicit The type of pair.second.
+ * \tparam T1 \deduced The argument pair type.
+ * \param [in] a1 The std::pair to be accessed.
+ * \returns The AttributeAccessor.
+ */
 template <typename A, typename B, typename T1>
 Ptr<const AttributeAccessor> MakePairAccessor(T1 a1);
 
@@ -171,6 +214,8 @@
 {
 
 /**
+ * \ingroup attribute_Pair
+ *
  * Internal checker class templated to each AttributeChecker
  * for each entry in the pair.
  */
@@ -273,18 +318,6 @@
 }
 
 template <class A, class B>
-PairValue<A, B>::PairValue()
-    : m_value(std::make_pair(Create<A>(), Create<B>()))
-{
-}
-
-template <class A, class B>
-PairValue<A, B>::PairValue(const typename PairValue<A, B>::result_type& value)
-{
-    Set(value);
-}
-
-template <class A, class B>
 Ptr<AttributeValue>
 PairValue<A, B>::Copy() const
 {
@@ -374,14 +407,6 @@
     return true;
 }
 
-/**
- * Create an AttributeAccessor for std::pair<>.
- * \tparam A \explicit The type of pair.first.
- * \tparam B \explicit The type of pair.second.
- * \tparam T1 \deduced The argument pair type.
- * \param [in] a1 The std::pair to be accessed.
- * \returns The AttributeAccessor.
- */
 template <typename A, typename B, typename T1>
 Ptr<const AttributeAccessor>
 MakePairAccessor(T1 a1)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/pointer.cc ns-3.42/src/core/model/pointer.cc
--- ns-3.41/src/core/model/pointer.cc	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/pointer.cc	2024-05-29 15:29:46.936073000 -0700
@@ -40,7 +40,7 @@
     NS_LOG_FUNCTION(this);
 }
 
-PointerValue::PointerValue(Ptr<Object> object)
+PointerValue::PointerValue(const Ptr<Object>& object)
     : m_value(object)
 {
     NS_LOG_FUNCTION(object);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/pointer.h ns-3.42/src/core/model/pointer.h
--- ns-3.41/src/core/model/pointer.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/pointer.h	2024-05-29 15:29:46.936073000 -0700
@@ -31,8 +31,19 @@
 namespace ns3
 {
 
-//  Additional docs for class PointerValue:
-/** Hold objects of type Ptr<T>. */
+/**
+ * \ingroup attributes
+ * \defgroup attribute_Pointer Pointer Attribute
+ * AttributeValue implementation for Pointer.
+ * Hold objects of type Ptr<T>.
+ */
+
+/**
+ * \ingroup attribute_Pointer
+ * \class  ns3::PointerValue "pointer.h"
+ * AttributeValue implementation for Pointer. Hold objects of type Ptr<T>.
+ * \see AttributeValue
+ */
 class PointerValue : public AttributeValue
 {
   public:
@@ -43,7 +54,7 @@
      *
      * \param [in] object The object to begin with.
      */
-    PointerValue(Ptr<Object> object);
+    PointerValue(const Ptr<Object>& object);
 
     /**
      * Set the value from by reference an Object.
@@ -74,14 +85,26 @@
     template <typename T>
     operator Ptr<T>() const;
 
-    // Documentation generated by print-introspected-doxygen.cc
+    /**
+     * Set the value.
+     * \param [in] value The value to adopt.
+     */
     template <typename T>
     void Set(const Ptr<T>& value);
 
-    /** \tparam T \explicit The type to cast to. */
+    /**
+     * \returns The Pointer value.
+     * \tparam T \explicit The type to cast to.
+     */
     template <typename T>
     Ptr<T> Get() const;
 
+    /**
+     * Access the Pointer value as type \p T.
+     * \tparam T \explicit The type to cast to.
+     * \param [out] value The Pointer value, as type \p T.
+     * \returns true.
+     */
     template <typename T>
     bool GetAccessor(Ptr<T>& value) const;
 
@@ -90,9 +113,14 @@
     bool DeserializeFromString(std::string value, Ptr<const AttributeChecker> checker) override;
 
   private:
-    Ptr<Object> m_value;
+    Ptr<Object> m_value; //!< The stored Pointer instance.
 };
 
+/**
+ * \ingroup attribute_Pointer
+ * AttributeChecker implementation for PointerValue.
+ * \see AttributeChecker
+ */
 class PointerChecker : public AttributeChecker
 {
   public:
@@ -104,6 +132,7 @@
 };
 
 /**
+ * \ingroup attribute_Pointer
  * Create a PointerChecker for a type.
  * \tparam T \explicit The underlying type.
  * \returns The PointerChecker.
@@ -123,7 +152,10 @@
 namespace internal
 {
 
-/** PointerChecker implementation. */
+/**
+ * \ingroup attribute_Pointer
+ *  PointerChecker implementation.
+ */
 template <typename T>
 class PointerChecker : public ns3::PointerChecker
 {
@@ -226,6 +258,23 @@
 
 ATTRIBUTE_ACCESSOR_DEFINE(Pointer);
 
+// Documentation of the functions defined by the macro.
+// not documented by print-introspected-doxygen because
+// Pointer has custom functions.
+
+/**
+ * \ingroup attribute_Pointer
+ * \fn ns3::Ptr<const ns3::AttributeAccessor> ns3::MakePointerAccessor (T1 a1)
+ * \copydoc ns3::MakeAccessorHelper(T1)
+ * \see AttributeAccessor
+ */
+/**
+ * \ingroup attribute_Pointer
+ * \fn ns3::Ptr<const ns3::AttributeAccessor> ns3::MakePointerAccessor (T1 a1, T2 a2)
+ * \copydoc ns3::MakeAccessorHelper(T1,T2)
+ * \see AttributeAccessor
+ */
+
 template <typename T>
 Ptr<AttributeChecker>
 MakePointerChecker()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/ptr.h ns-3.42/src/core/model/ptr.h
--- ns-3.41/src/core/model/ptr.h	2024-02-09 14:44:07.881790000 -0800
+++ ns-3.42/src/core/model/ptr.h	2024-05-29 15:29:46.936073000 -0700
@@ -401,6 +401,9 @@
     }
 };
 
+namespace internal
+{
+
 // Duplicate of struct EventMemberImplObjTraits<T> as defined in make-event.h
 // We repeat it here to declare a specialization on Ptr<T>
 // without making this header dependent on make-event.h
@@ -428,6 +431,8 @@
     }
 };
 
+} // namespace internal
+
 } // namespace ns3
 
 namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/scheduler.h ns-3.42/src/core/model/scheduler.h
--- ns-3.41/src/core/model/scheduler.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/scheduler.h	2024-05-29 15:29:46.936073000 -0700
@@ -229,7 +229,7 @@
 };
 
 /**
- * \ingroup Events
+ * \ingroup events
  * Compare (equal) two events by EventKey.
  *
  * \param [in] a The first event.
@@ -243,7 +243,7 @@
 }
 
 /**
- * \ingroup Events
+ * \ingroup events
  * Compare (not equal) two events by EventKey.
  *
  * \param [in] a The first event.
@@ -257,7 +257,7 @@
 }
 
 /**
- * \ingroup Events
+ * \ingroup events
  * Compare (less than) two events by EventKey.
  *
  * Note the invariants which this function must provide:
@@ -272,18 +272,7 @@
 inline bool
 operator<(const Scheduler::EventKey& a, const Scheduler::EventKey& b)
 {
-    if (a.m_ts < b.m_ts)
-    {
-        return true;
-    }
-    else if (a.m_ts == b.m_ts && a.m_uid < b.m_uid)
-    {
-        return true;
-    }
-    else
-    {
-        return false;
-    }
+    return (a.m_ts < b.m_ts || (a.m_ts == b.m_ts && a.m_uid < b.m_uid));
 }
 
 /**
@@ -296,18 +285,7 @@
 inline bool
 operator>(const Scheduler::EventKey& a, const Scheduler::EventKey& b)
 {
-    if (a.m_ts > b.m_ts)
-    {
-        return true;
-    }
-    else if (a.m_ts == b.m_ts && a.m_uid > b.m_uid)
-    {
-        return true;
-    }
-    else
-    {
-        return false;
-    }
+    return (a.m_ts > b.m_ts || (a.m_ts == b.m_ts && a.m_uid > b.m_uid));
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/shuffle.h ns-3.42/src/core/model/shuffle.h
--- ns-3.41/src/core/model/shuffle.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/core/model/shuffle.h	2024-05-29 15:29:46.936073000 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2024 Universita' degli Studi di Napoli Federico II
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Stefano Avallone <stavallo@unina.it>
+ */
+
+#ifndef SHUFFLE_H
+#define SHUFFLE_H
+
+/**
+ * \file
+ * \ingroup randomvariable
+ * Function to shuffle elements in a given range.
+ */
+
+#include "random-variable-stream.h"
+
+#include <algorithm>
+#include <iterator>
+
+namespace ns3
+{
+
+/**
+ * Shuffle the elements in the range <i>first</i> to <i>last</i>. Given that the implementation
+ * of std::shuffle is not dictated by the standard
+ * [CppReference](https://en.cppreference.com/w/cpp/algorithm/random_shuffle), it is not guaranteed
+ * that std::shuffle returns the same permutation of the given range using different compilers/OSes.
+ * Therefore, this function provides a specific implementation of the shuffling algorithm reported
+ * in "The Art of Computer Programming" of Donald Knuth and on
+ * [Wikipedia](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm),
+ * which basically matches the implementation in libstdc++.
+ *
+ * The complexity of the implemented algorithm is linear with the distance between <i>first</i>
+ * and <i>last</i>. For containers that do not provide random access iterators (e.g., lists, sets)
+ * we can still achieve a linear complexity by copying the elements in a vector and shuffling the
+ * elements of the vector.
+ *
+ * \tparam RND_ACCESS_ITER \deduced the iterator type (must be a random access iterator)
+ * \param first an iterator pointing to the first element in the range to shuffle
+ * \param last an iterator pointing to past-the-last element in the range to shuffle
+ * \param rv pointer to a uniform random variable
+ */
+template <typename RND_ACCESS_ITER>
+void
+Shuffle(RND_ACCESS_ITER first, RND_ACCESS_ITER last, Ptr<UniformRandomVariable> rv)
+{
+    if (auto dist = std::distance(first, last); dist > 1)
+    {
+        for (--last; first < last; ++first, --dist)
+        {
+            if (auto i = rv->GetInteger(0, dist - 1); i != 0)
+            {
+                std::iter_swap(first, std::next(first, i));
+            }
+        }
+    }
+}
+
+} // namespace ns3
+
+#endif /* SHUFFLE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/simulation-singleton.h ns-3.42/src/core/model/simulation-singleton.h
--- ns-3.41/src/core/model/simulation-singleton.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/simulation-singleton.h	2024-05-29 15:29:46.936073000 -0700
@@ -21,7 +21,7 @@
 
 /**
  * \file
- * \ingroup core
+ * \ingroup singleton
  * ns3::SimulationSingleton declaration and template implementation.
  */
 
@@ -29,7 +29,7 @@
 {
 
 /**
- * \ingroup core
+ * \ingroup singleton
  * This singleton class template ensures that the type
  * for which we want a singleton has a lifetime bounded
  * by the simulation run lifetime. That it, the underlying
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/simulator.h ns-3.42/src/core/model/simulator.h
--- ns-3.41/src/core/model/simulator.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/simulator.h	2024-05-29 15:29:46.936073000 -0700
@@ -426,7 +426,7 @@
      * Note that it is not possible to test for the expiration of
      * events which were scheduled for the "destroy" time. Doing so
      * will result in a program error (crash).
-     * An event is said to "expire" when it starts being scheduled
+     * An event is said to "expire" when it starts being executed,
      * which means that if the code executed by the event calls
      * this function, it will get true.
      *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/singleton.h ns-3.42/src/core/model/singleton.h
--- ns-3.41/src/core/model/singleton.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/singleton.h	2024-05-29 15:29:46.936073000 -0700
@@ -21,7 +21,7 @@
 
 /**
  * \file
- * \ingroup access
+ * \ingroup singleton
  * ns3::Singleton declaration and template implementation.
  */
 
@@ -29,7 +29,14 @@
 {
 
 /**
- * \ingroup access
+ * \ingroup core
+ * \defgroup singleton Singleton
+ *
+ * Template class implementing the Singleton design pattern.
+ */
+
+/**
+ * \ingroup singleton
  * \brief A template singleton
  *
  * This template class can be used to implement the singleton pattern.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/system-path.cc ns-3.42/src/core/model/system-path.cc
--- ns-3.41/src/core/model/system-path.cc	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/system-path.cc	2024-05-29 15:29:46.936073000 -0700
@@ -26,31 +26,11 @@
 
 #include <algorithm>
 #include <ctime>
+#include <filesystem>
 #include <regex>
 #include <sstream>
 #include <tuple>
 
-// Some compilers such as GCC < 8 (Ubuntu 18.04
-// ships with GCC 7) do not ship with the
-// std::filesystem header,  but with the
-// std::experimental::filesystem header.
-// Since Clang reuses these headers and the libstdc++
-// from GCC, we need to either use the experimental
-// version or require a more up-to-date GCC.
-// we use the "fs" namespace to prevent collisions
-// with musl libc.
-#ifdef __has_include
-#if __has_include(<filesystem>)
-#include <filesystem>
-namespace fs = std::filesystem;
-#elif __has_include(<experimental/filesystem>)
-#include <experimental/filesystem>
-namespace fs = std::experimental::filesystem;
-#else
-#error "No support for filesystem library"
-#endif
-#endif
-
 #ifdef __APPLE__
 #include <mach-o/dyld.h>
 #endif /* __APPLE__ */
@@ -107,13 +87,13 @@
 {
     NS_LOG_FUNCTION(path);
     std::list<std::string> files;
-    if (!fs::exists(path))
+    if (!std::filesystem::exists(path))
     {
         return std::make_tuple(files, true);
     }
-    for (auto& it : fs::directory_iterator(path))
+    for (auto& it : std::filesystem::directory_iterator(path))
     {
-        if (!fs::is_directory(it.path()))
+        if (!std::filesystem::is_directory(it.path()))
         {
             files.push_back(it.path().filename().string());
         }
@@ -189,7 +169,7 @@
     {
         //  LPTSTR = char *
         DWORD size = 1024;
-        LPTSTR lpFilename = (LPTSTR)malloc(sizeof(TCHAR) * size);
+        auto lpFilename = (LPTSTR)malloc(sizeof(TCHAR) * size);
         DWORD status = GetModuleFileName(nullptr, lpFilename, size);
         while (status == size)
         {
@@ -352,9 +332,9 @@
     NS_LOG_FUNCTION(path);
 
     std::error_code ec;
-    if (!fs::exists(path))
+    if (!std::filesystem::exists(path))
     {
-        fs::create_directories(path, ec);
+        std::filesystem::create_directories(path, ec);
     }
 
     if (ec.value())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/test.cc ns-3.42/src/core/model/test.cc
--- ns-3.41/src/core/model/test.cc	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/test.cc	2024-05-29 15:29:46.936073000 -0700
@@ -19,6 +19,7 @@
 
 #include "abort.h"
 #include "assert.h"
+#include "config.h"
 #include "des-metrics.h"
 #include "log.h"
 #include "singleton.h"
@@ -238,7 +239,7 @@
      */
     std::list<TestCase*> FilterTests(std::string testName,
                                      TestSuite::Type testType,
-                                     TestCase::TestDuration maximumTestDuration);
+                                     TestCase::Duration maximumTestDuration);
 
     /** Container type for the test. */
     typedef std::vector<TestSuite*> TestSuiteVector;
@@ -279,7 +280,7 @@
       m_runner(nullptr),
       m_result(nullptr),
       m_name(name),
-      m_duration(TestCase::QUICK)
+      m_duration(TestCase::Duration::QUICK)
 {
     NS_LOG_FUNCTION(this << name);
 }
@@ -298,7 +299,7 @@
 }
 
 void
-TestCase::AddTestCase(TestCase* testCase, TestCase::TestDuration duration)
+TestCase::AddTestCase(TestCase* testCase, TestCase::Duration duration)
 {
     NS_LOG_FUNCTION(&testCase << duration);
 
@@ -351,6 +352,7 @@
     NS_LOG_FUNCTION(this << runner);
     m_result = new Result();
     m_runner = runner;
+    Config::Reset();
     DoSetup();
     m_result->clock.Start();
     for (auto i = m_children.begin(); i != m_children.end(); ++i)
@@ -366,6 +368,7 @@
 out:
     m_result->clock.End();
     DoTeardown();
+    Config::Reset();
     m_runner = nullptr;
 }
 
@@ -796,11 +799,11 @@
     NS_LOG_FUNCTION(this << &begin << &end << printTestType);
     std::map<TestSuite::Type, std::string> label;
 
-    label[TestSuite::ALL] = "all          ";
-    label[TestSuite::UNIT] = "unit         ";
-    label[TestSuite::SYSTEM] = "system       ";
-    label[TestSuite::EXAMPLE] = "example      ";
-    label[TestSuite::PERFORMANCE] = "performance  ";
+    label[TestSuite::Type::ALL] = "all          ";
+    label[TestSuite::Type::UNIT] = "unit         ";
+    label[TestSuite::Type::SYSTEM] = "system       ";
+    label[TestSuite::Type::EXAMPLE] = "example      ";
+    label[TestSuite::Type::PERFORMANCE] = "performance  ";
 
     for (auto i = begin; i != end; ++i)
     {
@@ -833,14 +836,14 @@
 std::list<TestCase*>
 TestRunnerImpl::FilterTests(std::string testName,
                             TestSuite::Type testType,
-                            TestCase::TestDuration maximumTestDuration)
+                            TestCase::Duration maximumTestDuration)
 {
     NS_LOG_FUNCTION(this << testName << testType);
     std::list<TestCase*> tests;
     for (uint32_t i = 0; i < m_suites.size(); ++i)
     {
         TestSuite* test = m_suites[i];
-        if (testType != TestSuite::ALL && test->GetTestType() != testType)
+        if (testType != TestSuite::Type::ALL && test->GetTestType() != testType)
         {
             // skip test
             continue;
@@ -894,7 +897,7 @@
     bool printTestTypeList = false;
     bool printTestNameList = false;
     bool printTestTypeAndName = false;
-    TestCase::TestDuration maximumTestDuration = TestCase::QUICK;
+    TestCase::Duration maximumTestDuration = TestCase::Duration::QUICK;
     char* progname = argv[0];
 
     char** argi = argv;
@@ -924,11 +927,6 @@
         {
             m_updateData = true;
         }
-        else if (arg == "--help")
-        {
-            PrintHelp(progname);
-            return 0;
-        }
         else if (arg == "--print-test-name-list" || arg == "--list")
         {
             printTestNameList = true;
@@ -953,11 +951,8 @@
         {
             testTypeString = arg.substr(arg.find_first_of('=') + 1);
         }
-        else if (arg.find("--test-name=") != std::string::npos)
-        {
-            testName = arg.substr(arg.find_first_of('=') + 1);
-        }
-        else if (arg.find("--suite=") != std::string::npos)
+        else if (arg.find("--test-name=") != std::string::npos ||
+                 arg.find("--suite=") != std::string::npos)
         {
             testName = arg.substr(arg.find_first_of('=') + 1);
         }
@@ -976,15 +971,15 @@
             // Set the maximum test length allowed.
             if (fullness == "QUICK")
             {
-                maximumTestDuration = TestCase::QUICK;
+                maximumTestDuration = TestCase::Duration::QUICK;
             }
             else if (fullness == "EXTENSIVE")
             {
-                maximumTestDuration = TestCase::EXTENSIVE;
+                maximumTestDuration = TestCase::Duration::EXTENSIVE;
             }
             else if (fullness == "TAKES_FOREVER")
             {
-                maximumTestDuration = TestCase::TAKES_FOREVER;
+                maximumTestDuration = TestCase::Duration::TAKES_FOREVER;
             }
             else
             {
@@ -995,36 +990,32 @@
         }
         else
         {
-            // un-recognized command-line argument
+            // Print the help if arg == "--help" or arg is an un-recognized command-line argument
             PrintHelp(progname);
             return 0;
         }
         argi++;
     }
     TestSuite::Type testType;
-    if (testTypeString.empty())
+    if (testTypeString.empty() || testTypeString == "core")
     {
-        testType = TestSuite::ALL;
-    }
-    else if (testTypeString == "core")
-    {
-        testType = TestSuite::ALL;
+        testType = TestSuite::Type::ALL;
     }
     else if (testTypeString == "example")
     {
-        testType = TestSuite::EXAMPLE;
+        testType = TestSuite::Type::EXAMPLE;
     }
     else if (testTypeString == "unit")
     {
-        testType = TestSuite::UNIT;
+        testType = TestSuite::Type::UNIT;
     }
     else if (testTypeString == "system")
     {
-        testType = TestSuite::SYSTEM;
+        testType = TestSuite::Type::SYSTEM;
     }
     else if (testTypeString == "performance")
     {
-        testType = TestSuite::PERFORMANCE;
+        testType = TestSuite::Type::PERFORMANCE;
     }
     else
     {
@@ -1144,4 +1135,38 @@
     return TestRunnerImpl::Get()->Run(argc, argv);
 }
 
+std::ostream&
+operator<<(std::ostream& os, TestSuite::Type type)
+{
+    switch (type)
+    {
+    case TestSuite::Type::ALL:
+        return os << "ALL";
+    case TestSuite::Type::UNIT:
+        return os << "UNIT";
+    case TestSuite::Type::SYSTEM:
+        return os << "SYSTEM";
+    case TestSuite::Type::EXAMPLE:
+        return os << "EXAMPLE";
+    case TestSuite::Type::PERFORMANCE:
+        return os << "PERFORMANCE";
+    };
+    return os << "UNKNOWN(" << static_cast<uint32_t>(type) << ")";
+}
+
+std::ostream&
+operator<<(std::ostream& os, TestCase::Duration duration)
+{
+    switch (duration)
+    {
+    case TestCase::Duration::QUICK:
+        return os << "QUICK";
+    case TestCase::Duration::EXTENSIVE:
+        return os << "EXTENSIVE";
+    case TestCase::Duration::TAKES_FOREVER:
+        return os << "TAKES_FOREVER";
+    };
+    return os << "UNKNOWN(" << static_cast<uint32_t>(duration) << ")";
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/test.h ns-3.42/src/core/model/test.h
--- ns-3.41/src/core/model/test.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/test.h	2024-05-29 15:29:46.936073000 -0700
@@ -18,6 +18,7 @@
 #ifndef NS3_TEST_H
 #define NS3_TEST_H
 
+#include "deprecated.h"
 #include "system-wall-clock-ms.h"
 
 #include <fstream>
@@ -1060,13 +1061,24 @@
 {
   public:
     /** \brief How long the test takes to execute. */
-    enum TestDuration
+    enum class Duration
     {
         QUICK = 1,        //!< Fast test.
         EXTENSIVE = 2,    //!< Medium length test.
         TAKES_FOREVER = 3 //!< Very long running test.
     };
 
+    NS_DEPRECATED_3_42("Use Duration::QUICK instead")
+    static constexpr auto QUICK = Duration::QUICK; //!< @deprecated See Duration::QUICK.
+    NS_DEPRECATED_3_42("Use Duration::EXTENSIVE instead")
+    static constexpr auto EXTENSIVE = Duration::EXTENSIVE; //!< @deprecated See Duration::EXTENSIVE.
+    NS_DEPRECATED_3_42("Use Duration::TAKES_FOREVER instead")
+    static constexpr auto TAKES_FOREVER =
+        Duration::TAKES_FOREVER; //!< @deprecated See Duration::TAKES_FOREVER.
+
+    using TestDuration NS_DEPRECATED_3_42("Use Duration instead") =
+        Duration; //!< @deprecated See Duration.
+
     /**
      *  Destructor
      */
@@ -1096,7 +1108,7 @@
      * \param [in] duration Amount of time this test takes to execute
      *             (defaults to QUICK).
      */
-    void AddTestCase(TestCase* testCase, TestDuration duration = QUICK);
+    void AddTestCase(TestCase* testCase, Duration duration = Duration::QUICK);
 
     /**
      * \brief Set the data directory where reference trace files can be
@@ -1222,7 +1234,12 @@
 
     // methods called by TestRunnerImpl
     /**
-     * \brief Actually run this TestCase
+     * \brief Executes DoSetup(), DoRun(), and DoTeardown() for the TestCase
+     *
+     * Config::Reset() is called at both the beginning and end of this method
+     * so that any changes to attribute default values (Config::SetDefault(...))
+     * or global values (e.g., RngRun) that are made within the test case's
+     * DoRun() method do not propagate beyond the scope of running the TestCase.
      *
      * \param [in] runner The test runner implementation.
      */
@@ -1242,7 +1259,7 @@
     TestRunnerImpl* m_runner;          //!< Pointer to the TestRunner
     Result* m_result;                  //!< Results data
     std::string m_name;                //!< TestCase name
-    TestDuration m_duration;           //!< TestCase duration
+    Duration m_duration;               //!< TestCase duration
 };
 
 /**
@@ -1259,7 +1276,7 @@
      * \enum Type
      * \brief Type of test.
      */
-    enum Type
+    enum class Type
     {
         ALL = 0,    //!<
         UNIT,       //!< This test suite implements a Unit Test
@@ -1268,13 +1285,24 @@
         PERFORMANCE //!< This test suite implements a Performance Test
     };
 
+    NS_DEPRECATED_3_42("Use Type::ALL instead")
+    static constexpr auto ALL = Type::ALL; //!< @deprecated See Type::ALL.
+    NS_DEPRECATED_3_42("Use Type::UNIT instead")
+    static constexpr auto UNIT = Type::UNIT; //!< @deprecated See Type::UNIT.
+    NS_DEPRECATED_3_42("Use Type::SYSTEM instead")
+    static constexpr auto SYSTEM = Type::SYSTEM; //!< @deprecated See Type::SYSTEM.
+    NS_DEPRECATED_3_42("Use Type::EXAMPLE instead")
+    static constexpr auto EXAMPLE = Type::EXAMPLE; //!< @deprecated See Type::EXAMPLE.
+    NS_DEPRECATED_3_42("Use Type::PERFORMANCE instead")
+    static constexpr auto PERFORMANCE = Type::PERFORMANCE; //!< @deprecated See Type::PERFORMANCE.
+
     /**
      * \brief Construct a new test suite.
      *
      * \param [in] name The name of the test suite.
      * \param [in] type The TestType of the test suite (defaults to UNIT test).
      */
-    TestSuite(std::string name, Type type = UNIT);
+    TestSuite(std::string name, Type type = Type::UNIT);
 
     /**
      * \brief get the kind of test this test suite implements
@@ -1357,6 +1385,38 @@
      */
     T Get(std::size_t i) const;
 
+    /**
+     * \return The underlying data structure begin iterator
+     */
+    typename std::vector<T>::iterator begin()
+    {
+        return m_vectors.begin();
+    }
+
+    /**
+     * \return The underlying data structure end iterator
+     */
+    typename std::vector<T>::iterator end()
+    {
+        return m_vectors.end();
+    }
+
+    /**
+     * \return The underlying data structure const begin iterator
+     */
+    typename std::vector<T>::const_iterator begin() const
+    {
+        return m_vectors.begin();
+    }
+
+    /**
+     * \return The underlying data structure const end iterator
+     */
+    typename std::vector<T>::const_iterator end() const
+    {
+        return m_vectors.end();
+    }
+
   private:
     typedef std::vector<T> TestVector; //!< Container type
     TestVector m_vectors;              //!< The list of test vectors
@@ -1404,6 +1464,22 @@
     return m_vectors[i];
 }
 
+/**
+ * @brief Stream insertion operator.
+ * @param [in] os The reference to the output stream.
+ * @param [in] type The TestSuite::Type.
+ * @return The reference to the output stream.
+ */
+std::ostream& operator<<(std::ostream& os, TestSuite::Type type);
+
+/**
+ * @brief Stream insertion operator.
+ * @param [in] os The reference to the output stream.
+ * @param [in] duration The TestCase::Duration.
+ * @return The reference to the output stream.
+ */
+std::ostream& operator<<(std::ostream& os, TestCase::Duration duration);
+
 } // namespace ns3
 
 #endif /* NS3_TEST_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/timer.cc ns-3.42/src/core/model/timer.cc
--- ns-3.41/src/core/model/timer.cc	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/timer.cc	2024-05-29 15:29:46.936073000 -0700
@@ -56,7 +56,7 @@
     NS_LOG_FUNCTION(this);
     if (m_flags & CHECK_ON_DESTROY)
     {
-        if (m_event.IsRunning())
+        if (m_event.IsPending())
         {
             NS_FATAL_ERROR("Event is still running while destroying.");
         }
@@ -129,7 +129,7 @@
 Timer::IsRunning() const
 {
     NS_LOG_FUNCTION(this);
-    return !IsSuspended() && m_event.IsRunning();
+    return !IsSuspended() && m_event.IsPending();
 }
 
 bool
@@ -170,7 +170,7 @@
 {
     NS_LOG_FUNCTION(this << delay);
     NS_ASSERT(m_impl != nullptr);
-    if (m_event.IsRunning())
+    if (m_event.IsPending())
     {
         NS_FATAL_ERROR("Event is still running while re-scheduling.");
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/timer.h ns-3.42/src/core/model/timer.h
--- ns-3.41/src/core/model/timer.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/timer.h	2024-05-29 15:29:46.936073000 -0700
@@ -21,7 +21,6 @@
 
 #include "event-id.h"
 #include "fatal-error.h"
-#include "int-to-type.h"
 #include "nstime.h"
 
 /**
@@ -50,8 +49,13 @@
  * Timer is destroyed.
  */
 
+namespace internal
+{
+
 class TimerImpl;
 
+} // namespace internal
+
 /**
  * \ingroup timer
  * \brief A simple virtual Timer class
@@ -254,7 +258,7 @@
      * The timer implementation, which contains the bound callback
      * function and arguments.
      */
-    TimerImpl* m_impl;
+    internal::TimerImpl* m_impl;
     /** The amount of time left on the Timer while it is suspended. */
     Time m_delayLeft;
 };
@@ -275,7 +279,7 @@
 Timer::SetFunction(FN fn)
 {
     delete m_impl;
-    m_impl = MakeTimerImpl(fn);
+    m_impl = internal::MakeTimerImpl(fn);
 }
 
 template <typename MEM_PTR, typename OBJ_PTR>
@@ -283,7 +287,7 @@
 Timer::SetFunction(MEM_PTR memPtr, OBJ_PTR objPtr)
 {
     delete m_impl;
-    m_impl = MakeTimerImpl(memPtr, objPtr);
+    m_impl = internal::MakeTimerImpl(memPtr, objPtr);
 }
 
 template <typename... Ts>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/timer-impl.h ns-3.42/src/core/model/timer-impl.h
--- ns-3.41/src/core/model/timer-impl.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/timer-impl.h	2024-05-29 15:29:46.936073000 -0700
@@ -21,9 +21,9 @@
 #define TIMER_IMPL_H
 
 #include "fatal-error.h"
-#include "int-to-type.h"
 #include "simulator.h"
-#include "type-traits.h"
+
+#include <type_traits>
 
 /**
  * \file
@@ -35,6 +35,9 @@
 namespace ns3
 {
 
+namespace internal
+{
+
 /**
  * \ingroup timer
  * The timer implementation underlying Timer and Watchdog.
@@ -49,75 +52,12 @@
 
     /**
      * Set the arguments to be used when invoking the expire function.
+     *
+     * \tparam Args \deduced Type template parameter pack
+     * \param [in] args The arguments to pass to the invoked method
      */
-    /**@{*/
-    /**
-     * \tparam T1 \deduced Type of the first argument.
-     * \param [in] a1 The first argument
-     */
-    template <typename T1>
-    void SetArgs(T1 a1);
-    /**
-     * \tparam T1 \deduced Type of the first argument.
-     * \tparam T2 \deduced Type of the second argument.
-     * \param [in] a1 the first argument
-     * \param [in] a2 the second argument
-     */
-    template <typename T1, typename T2>
-    void SetArgs(T1 a1, T2 a2);
-    /**
-     * \tparam T1 \deduced Type of the first argument.
-     * \tparam T2 \deduced Type of the second argument.
-     * \tparam T3 \deduced Type of the third argument.
-     * \param [in] a1 the first argument
-     * \param [in] a2 the second argument
-     * \param [in] a3 the third argument
-     */
-    template <typename T1, typename T2, typename T3>
-    void SetArgs(T1 a1, T2 a2, T3 a3);
-    /**
-     * \tparam T1 \deduced Type of the first argument.
-     * \tparam T2 \deduced Type of the second argument.
-     * \tparam T3 \deduced Type of the third argument.
-     * \tparam T4 \deduced Type of the fourth argument.
-     * \param [in] a1 the first argument
-     * \param [in] a2 the second argument
-     * \param [in] a3 the third argument
-     * \param [in] a4 the fourth argument
-     */
-    template <typename T1, typename T2, typename T3, typename T4>
-    void SetArgs(T1 a1, T2 a2, T3 a3, T4 a4);
-    /**
-     * \tparam T1 \deduced Type of the first argument.
-     * \tparam T2 \deduced Type of the second argument.
-     * \tparam T3 \deduced Type of the third argument.
-     * \tparam T4 \deduced Type of the fourth argument.
-     * \tparam T5 \deduced Type of the fifth argument.
-     * \param [in] a1 the first argument
-     * \param [in] a2 the second argument
-     * \param [in] a3 the third argument
-     * \param [in] a4 the fourth argument
-     * \param [in] a5 the fifth argument
-     */
-    template <typename T1, typename T2, typename T3, typename T4, typename T5>
-    void SetArgs(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
-    /**
-     * \tparam T1 \deduced Type of the first argument.
-     * \tparam T2 \deduced Type of the second argument.
-     * \tparam T3 \deduced Type of the third argument.
-     * \tparam T4 \deduced Type of the fourth argument.
-     * \tparam T5 \deduced Type of the fifth argument.
-     * \tparam T6 \deduced Type of the sixth argument.
-     * \param [in] a1 the first argument
-     * \param [in] a2 the second argument
-     * \param [in] a3 the third argument
-     * \param [in] a4 the fourth argument
-     * \param [in] a5 the fifth argument
-     * \param [in] a6 the sixth argument
-     */
-    template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
-    void SetArgs(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);
-    /**@}*/
+    template <typename... Args>
+    void SetArgs(Args... args);
 
     /**
      * Schedule the callback for a future time.
@@ -130,946 +70,114 @@
     virtual void Invoke() = 0;
 };
 
-} // namespace ns3
-
 /********************************************************************
  *  Implementation of TimerImpl implementation functions.
  ********************************************************************/
 
-namespace ns3
-{
-
 /**
  * \ingroup timer
  * \defgroup timerimpl TimerImpl Implementation
  * @{
  */
-
-/** TimerImpl specialization class for varying numbers of arguments. */
-template <typename T1>
-struct TimerImplOne : public TimerImpl
-{
-    /**
-     * Bind the arguments to be used when the callback function is invoked.
-     *
-     * \param [in] a1 The first argument.
-     */
-    virtual void SetArguments(T1 a1) = 0;
-};
-
-/** TimerImpl specialization class for varying numbers of arguments. */
-template <typename T1, typename T2>
-struct TimerImplTwo : public TimerImpl
-{
-    /**
-     * Bind the arguments to be used when the callback function is invoked.
-     *
-     * \param [in] a1 The first argument.
-     * \param [in] a2 The second argument.
-     */
-    virtual void SetArguments(T1 a1, T2 a2) = 0;
-};
-
-/** TimerImpl specialization class for varying numbers of arguments. */
-template <typename T1, typename T2, typename T3>
-struct TimerImplThree : public TimerImpl
-{
-    /**
-     * Bind the arguments to be used when the callback function is invoked.
-     *
-     * \param [in] a1 The first argument.
-     * \param [in] a2 The second argument.
-     * \param [in] a3 The third argument.
-     */
-    virtual void SetArguments(T1 a1, T2 a2, T3 a3) = 0;
-};
-
-/** TimerImpl specialization class for varying numbers of arguments. */
-template <typename T1, typename T2, typename T3, typename T4>
-struct TimerImplFour : public TimerImpl
-{
-    /**
-     * Bind the arguments to be used when the callback function is invoked.
-     *
-     * \param [in] a1 The first argument.
-     * \param [in] a2 The second argument.
-     * \param [in] a3 The third argument.
-     * \param [in] a4 The fourth argument.
-     */
-    virtual void SetArguments(T1 a1, T2 a2, T3 a3, T4 a4) = 0;
-};
-
 /** TimerImpl specialization class for varying numbers of arguments. */
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-struct TimerImplFive : public TimerImpl
+template <typename... Args>
+struct TimerImplX : public TimerImpl
 {
     /**
      * Bind the arguments to be used when the callback function is invoked.
      *
-     * \param [in] a1 The first argument.
-     * \param [in] a2 The second argument.
-     * \param [in] a3 The third argument.
-     * \param [in] a4 The fourth argument.
-     * \param [in] a5 The fifth argument.
+     * \param [in] args The arguments to pass to the invoked method.
      */
-    virtual void SetArguments(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) = 0;
-};
-
-/** TimerImpl specialization class for varying numbers of arguments. */
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
-struct TimerImplSix : public TimerImpl
-{
-    /**
-     * Bind the arguments to be used when the callback function is invoked.
-     *
-     * \param [in] a1 The first argument.
-     * \param [in] a2 The second argument.
-     * \param [in] a3 The third argument.
-     * \param [in] a4 The fourth argument.
-     * \param [in] a5 The fifth argument.
-     * \param [in] a6 The sixth argument.
-     */
-    virtual void SetArguments(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) = 0;
-};
-
-/** Type and reference traits for TimerImpl arguments. */
-template <typename T>
-struct TimerTraits
-{
-    /** Storage type for an argument. */
-    typedef typename TypeTraits<typename TypeTraits<T>::ReferencedType>::NonConstType StoredType;
-    /** Parameter type for an argument. */
-    typedef const StoredType& ParameterType;
+    virtual void SetArguments(Args... args) = 0;
 };
 
 /**
  * Make a TimerImpl from a function pointer taking varying numbers of arguments.
  *
- * \tparam FN \deduced Function signature type of the callback function.
- * \param [in] fn The function pointer to invoke when the timer expires.
+ * \tparam U \deduced Return type of the callback function.
+ * \tparam Ts \deduced Argument types of the callback function.
  * \returns The TimerImpl.
  */
-template <typename FN>
+template <typename U, typename... Ts>
 TimerImpl*
-MakeTimerImpl(FN fn)
+MakeTimerImpl(U(fn)(Ts...))
 {
-    NS_ASSERT(TypeTraits<FN>::IsFunctionPointer);
-    return MakeTimerImpl(IntToType<TypeTraits<FN>::FunctionPointerTraits::nArgs>(), fn);
-}
-
-/**
- * Make a TimerImpl from a function pointer taking zero arguments.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<0>, FN fn)
-{
-    struct FnTimerImplZero : public TimerImpl
+    struct FnTimerImpl : public TimerImplX<const std::remove_cvref_t<Ts>&...>
     {
-        FnTimerImplZero(FN fn)
+        FnTimerImpl(void (*fn)(Ts...))
             : m_fn(fn)
         {
         }
 
-        EventId Schedule(const Time& delay) override
+        void SetArguments(const std::remove_cvref_t<Ts>&... args) override
         {
-            return Simulator::Schedule(delay, m_fn);
-        }
-
-        void Invoke() override
-        {
-            m_fn();
-        }
-
-        FN m_fn;
-    }* function = new FnTimerImplZero(fn);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking one argument.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<1>, FN fn)
-{
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-
-    struct FnTimerImplOne : public TimerImplOne<T1Parameter>
-    {
-        FnTimerImplOne(FN fn)
-            : m_fn(fn)
-        {
-        }
-
-        void SetArguments(T1Parameter a1) override
-        {
-            m_a1 = a1;
+            m_arguments = std::tuple(args...);
         }
 
         EventId Schedule(const Time& delay) override
         {
-            return Simulator::Schedule(delay, m_fn, m_a1);
+            return std::apply(
+                [&, this](Ts... args) { return Simulator::Schedule(delay, m_fn, args...); },
+                m_arguments);
         }
 
         void Invoke() override
         {
-            m_fn(m_a1);
-        }
-
-        FN m_fn;
-        T1Stored m_a1;
-    }* function = new FnTimerImplOne(fn);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking two arguments.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<2>, FN fn)
-{
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-
-    struct FnTimerImplTwo : public TimerImplTwo<T1Parameter, T2Parameter>
-    {
-        FnTimerImplTwo(FN fn)
-            : m_fn(fn)
-        {
-        }
-
-        void SetArguments(T1Parameter a1, T2Parameter a2) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_fn, m_a1, m_a2);
-        }
-
-        void Invoke() override
-        {
-            m_fn(m_a1, m_a2);
-        }
-
-        FN m_fn;
-        T1Stored m_a1;
-        T2Stored m_a2;
-    }* function = new FnTimerImplTwo(fn);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking three arguments.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<3>, FN fn)
-{
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-
-    struct FnTimerImplThree : public TimerImplThree<T1Parameter, T2Parameter, T3Parameter>
-    {
-        FnTimerImplThree(FN fn)
-            : m_fn(fn)
-        {
-        }
-
-        void SetArguments(T1Parameter a1, T2Parameter a2, T3Parameter a3) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_fn, m_a1, m_a2, m_a3);
-        }
-
-        void Invoke() override
-        {
-            m_fn(m_a1, m_a2, m_a3);
-        }
-
-        FN m_fn;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-    }* function = new FnTimerImplThree(fn);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking four arguments.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<4>, FN fn)
-{
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg4Type T4;
-    typedef typename TimerTraits<T4>::ParameterType T4Parameter;
-    typedef typename TimerTraits<T4>::StoredType T4Stored;
-
-    struct FnTimerImplFour
-        : public TimerImplFour<T1Parameter, T2Parameter, T3Parameter, T4Parameter>
-    {
-        FnTimerImplFour(FN fn)
-            : m_fn(fn)
-        {
-        }
-
-        void SetArguments(T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-            m_a4 = a4;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_fn, m_a1, m_a2, m_a3, m_a4);
-        }
-
-        void Invoke() override
-        {
-            m_fn(m_a1, m_a2, m_a3, m_a4);
-        }
-
-        FN m_fn;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-        T4Stored m_a4;
-    }* function = new FnTimerImplFour(fn);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking five arguments.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<5>, FN fn)
-{
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg4Type T4;
-    typedef typename TimerTraits<T4>::ParameterType T4Parameter;
-    typedef typename TimerTraits<T4>::StoredType T4Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg5Type T5;
-    typedef typename TimerTraits<T5>::ParameterType T5Parameter;
-    typedef typename TimerTraits<T5>::StoredType T5Stored;
-
-    struct FnTimerImplFive
-        : public TimerImplFive<T1Parameter, T2Parameter, T3Parameter, T4Parameter, T5Parameter>
-    {
-        FnTimerImplFive(FN fn)
-            : m_fn(fn)
-        {
-        }
-
-        void SetArguments(T1Parameter a1,
-                          T2Parameter a2,
-                          T3Parameter a3,
-                          T4Parameter a4,
-                          T5Parameter a5) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-            m_a4 = a4;
-            m_a5 = a5;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_fn, m_a1, m_a2, m_a3, m_a4, m_a5);
-        }
-
-        void Invoke() override
-        {
-            m_fn(m_a1, m_a2, m_a3, m_a4, m_a5);
-        }
-
-        FN m_fn;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-        T4Stored m_a4;
-        T5Stored m_a5;
-    }* function = new FnTimerImplFive(fn);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking six arguments.
- * \copydetails MakeTimerImpl(FN)
- */
-template <typename FN>
-TimerImpl*
-MakeTimerImpl(IntToType<6>, FN fn)
-{
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg4Type T4;
-    typedef typename TimerTraits<T4>::ParameterType T4Parameter;
-    typedef typename TimerTraits<T4>::StoredType T4Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg5Type T5;
-    typedef typename TimerTraits<T5>::ParameterType T5Parameter;
-    typedef typename TimerTraits<T5>::StoredType T5Stored;
-    typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg6Type T6;
-    typedef typename TimerTraits<T6>::ParameterType T6Parameter;
-    typedef typename TimerTraits<T6>::StoredType T6Stored;
-
-    struct FnTimerImplSix : public TimerImplSix<T1Parameter,
-                                                T2Parameter,
-                                                T3Parameter,
-                                                T4Parameter,
-                                                T5Parameter,
-                                                T6Parameter>
-    {
-        FnTimerImplSix(FN fn)
-            : m_fn(fn)
-        {
-        }
-
-        virtual void SetArguments(T1Parameter a1,
-                                  T2Parameter a2,
-                                  T3Parameter a3,
-                                  T4Parameter a4,
-                                  T5Parameter a5,
-                                  T6Parameter a6)
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-            m_a4 = a4;
-            m_a5 = a5;
-            m_a6 = a6;
-        }
-
-        virtual EventId Schedule(const Time& delay)
-        {
-            return Simulator::Schedule(delay, m_fn, m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
-        }
-
-        virtual void Invoke()
-        {
-            m_fn(m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
+            std::apply([this](Ts... args) { (m_fn)(args...); }, m_arguments);
         }
 
-        FN m_fn;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-        T4Stored m_a4;
-        T5Stored m_a5;
-        T6Stored m_a6;
-    }* function = new FnTimerImplSix(fn);
+        decltype(fn) m_fn;
+        std::tuple<std::remove_cvref_t<Ts>...> m_arguments;
+    }* function = new FnTimerImpl(fn);
 
     return function;
 }
 
 /**
- * Helper for the MakeTimerImpl functions which take a class method.
- *
- * This helper converts a pointer to a reference.
- *
- * This is the generic template declaration (with empty body).
- *
- * \tparam T \explicit The object type.
- */
-template <typename T>
-struct TimerImplMemberTraits;
-
-/**
- * Helper for the MakeTimerImpl functions which take a class method.
- *
- * This helper converts a pointer to a reference.
- *
- * This is the specialization for pointer to \c T.
- *
- * \tparam T \explicit The object type.
- */
-template <typename T>
-struct TimerImplMemberTraits<T*>
-{
-    /**
-     * Convert a pointer type to a reference.
-     *
-     * \param [in] p The pointer.
-     * \returns A reference to the object pointed to by \c p.
-     */
-    static T& GetReference(T* p)
-    {
-        return *p;
-    }
-};
-
-/**
  * Make a TimerImpl from a class method pointer taking
  * a varying number of arguments.
  *
- * \tparam MEM_PTR \deduced Class method function signature type.
  * \tparam OBJ_PTR \deduced Class type.
+ * \tparam U \deduced Class method function return type.
+ * \tparam V \deduced Class method function class type.
+ * \tparam Ts \deduced Class method function argument types.
  * \param [in] memPtr Class method to invoke when the timer expires.
  * \param [in] objPtr Object instance pointer.
  * \returns The TimerImpl.
  */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    NS_ASSERT(TypeTraits<MEM_PTR>::IsPointerToMember);
-    return MakeTimerImpl(IntToType<TypeTraits<MEM_PTR>::PointerToMemberTraits::nArgs>(),
-                         memPtr,
-                         objPtr);
-}
-
-/**
- * Make a TimerImpl from a function pointer taking zero arguments.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
+template <typename OBJ_PTR, typename U, typename V, typename... Ts>
 TimerImpl*
-MakeTimerImpl(IntToType<0>, MEM_PTR memPtr, OBJ_PTR objPtr)
+MakeTimerImpl(U (V::*memPtr)(Ts...), OBJ_PTR objPtr)
 {
-    struct MemFnTimerImplZero : public TimerImpl
+    struct MemFnTimerImpl : public TimerImplX<const std::remove_cvref_t<Ts>&...>
     {
-        MemFnTimerImplZero(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
+        MemFnTimerImpl(decltype(memPtr) memPtr, OBJ_PTR objPtr)
+            : m_memPtr(std::bind_front(memPtr, objPtr))
         {
         }
 
-        EventId Schedule(const Time& delay) override
+        void SetArguments(const std::remove_cvref_t<Ts>&... args) override
         {
-            return Simulator::Schedule(delay, m_memPtr, m_objPtr);
-        }
-
-        void Invoke() override
-        {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*m_memPtr)();
-        }
-
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-    }* function = new MemFnTimerImplZero(memPtr, objPtr);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking one argument.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(IntToType<1>, MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-
-    struct MemFnTimerImplOne : public TimerImplOne<T1Parameter>
-    {
-        MemFnTimerImplOne(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
-        {
-        }
-
-        void SetArguments(T1Parameter a1) override
-        {
-            m_a1 = a1;
+            m_arguments = std::tuple(args...);
         }
 
         EventId Schedule(const Time& delay) override
         {
-            return Simulator::Schedule(delay, m_memPtr, m_objPtr, m_a1);
+            return std::apply(
+                [&, this](Ts... args) {
+                    return Simulator::Schedule(delay, std::bind(m_memPtr, args...));
+                },
+                m_arguments);
         }
 
         void Invoke() override
         {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*m_memPtr)(m_a1);
+            std::apply(m_memPtr, m_arguments);
         }
 
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-        T1Stored m_a1;
-    }* function = new MemFnTimerImplOne(memPtr, objPtr);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking two arguments.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(IntToType<2>, MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-
-    struct MemFnTimerImplTwo : public TimerImplTwo<T1Parameter, T2Parameter>
-    {
-        MemFnTimerImplTwo(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
-        {
-        }
-
-        void SetArguments(T1Parameter a1, T2Parameter a2) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_memPtr, m_objPtr, m_a1, m_a2);
-        }
-
-        void Invoke() override
-        {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*m_memPtr)(m_a1, m_a2);
-        }
-
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-        T1Stored m_a1;
-        T2Stored m_a2;
-    }* function = new MemFnTimerImplTwo(memPtr, objPtr);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking three arguments.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(IntToType<3>, MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-
-    struct MemFnTimerImplThree : public TimerImplThree<T1Parameter, T2Parameter, T3Parameter>
-    {
-        MemFnTimerImplThree(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
-        {
-        }
-
-        void SetArguments(T1Parameter a1, T2Parameter a2, T3Parameter a3) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3);
-        }
-
-        void Invoke() override
-        {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*m_memPtr)(m_a1, m_a2, m_a3);
-        }
-
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-    }* function = new MemFnTimerImplThree(memPtr, objPtr);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking four arguments.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(IntToType<4>, MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg4Type T4;
-    typedef typename TimerTraits<T4>::ParameterType T4Parameter;
-    typedef typename TimerTraits<T4>::StoredType T4Stored;
-
-    struct MemFnTimerImplFour
-        : public TimerImplFour<T1Parameter, T2Parameter, T3Parameter, T4Parameter>
-    {
-        MemFnTimerImplFour(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
-        {
-        }
-
-        void SetArguments(T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-            m_a4 = a4;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4);
-        }
-
-        void Invoke() override
-        {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*
-             m_memPtr)(m_a1, m_a2, m_a3, m_a4);
-        }
-
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-        T4Stored m_a4;
-    }* function = new MemFnTimerImplFour(memPtr, objPtr);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking five arguments.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(IntToType<5>, MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg4Type T4;
-    typedef typename TimerTraits<T4>::ParameterType T4Parameter;
-    typedef typename TimerTraits<T4>::StoredType T4Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg5Type T5;
-    typedef typename TimerTraits<T5>::ParameterType T5Parameter;
-    typedef typename TimerTraits<T5>::StoredType T5Stored;
-
-    struct MemFnTimerImplFive
-        : public TimerImplFive<T1Parameter, T2Parameter, T3Parameter, T4Parameter, T5Parameter>
-    {
-        MemFnTimerImplFive(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
-        {
-        }
-
-        void SetArguments(T1Parameter a1,
-                          T2Parameter a2,
-                          T3Parameter a3,
-                          T4Parameter a4,
-                          T5Parameter a5) override
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-            m_a4 = a4;
-            m_a5 = a5;
-        }
-
-        EventId Schedule(const Time& delay) override
-        {
-            return Simulator::Schedule(delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4, m_a5);
-        }
-
-        void Invoke() override
-        {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*
-             m_memPtr)(m_a1, m_a2, m_a3, m_a4, m_a5);
-        }
-
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-        T4Stored m_a4;
-        T5Stored m_a5;
-    }* function = new MemFnTimerImplFive(memPtr, objPtr);
-
-    return function;
-}
-
-/**
- * Make a TimerImpl from a function pointer taking six arguments.
- * \copydetails MakeTimerImpl(MEM_PTR,OBJ_PTR)
- */
-template <typename MEM_PTR, typename OBJ_PTR>
-TimerImpl*
-MakeTimerImpl(IntToType<6>, MEM_PTR memPtr, OBJ_PTR objPtr)
-{
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
-    typedef typename TimerTraits<T1>::ParameterType T1Parameter;
-    typedef typename TimerTraits<T1>::StoredType T1Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
-    typedef typename TimerTraits<T2>::ParameterType T2Parameter;
-    typedef typename TimerTraits<T2>::StoredType T2Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
-    typedef typename TimerTraits<T3>::ParameterType T3Parameter;
-    typedef typename TimerTraits<T3>::StoredType T3Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg4Type T4;
-    typedef typename TimerTraits<T4>::ParameterType T4Parameter;
-    typedef typename TimerTraits<T4>::StoredType T4Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg5Type T5;
-    typedef typename TimerTraits<T5>::ParameterType T5Parameter;
-    typedef typename TimerTraits<T5>::StoredType T5Stored;
-    typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg6Type T6;
-    typedef typename TimerTraits<T6>::ParameterType T6Parameter;
-    typedef typename TimerTraits<T6>::StoredType T6Stored;
-
-    struct MemFnTimerImplSix : public TimerImplSix<T1Parameter,
-                                                   T2Parameter,
-                                                   T3Parameter,
-                                                   T4Parameter,
-                                                   T5Parameter,
-                                                   T6Parameter>
-    {
-        MemFnTimerImplSix(MEM_PTR memPtr, OBJ_PTR objPtr)
-            : m_memPtr(memPtr),
-              m_objPtr(objPtr)
-        {
-        }
-
-        virtual void SetArguments(T1Parameter a1,
-                                  T2Parameter a2,
-                                  T3Parameter a3,
-                                  T4Parameter a4,
-                                  T5Parameter a5,
-                                  T6Parameter a6)
-        {
-            m_a1 = a1;
-            m_a2 = a2;
-            m_a3 = a3;
-            m_a4 = a4;
-            m_a5 = a5;
-            m_a6 = a6;
-        }
-
-        virtual EventId Schedule(const Time& delay)
-        {
-            return Simulator::Schedule(delay,
-                                       m_memPtr,
-                                       m_objPtr,
-                                       m_a1,
-                                       m_a2,
-                                       m_a3,
-                                       m_a4,
-                                       m_a5,
-                                       m_a6);
-        }
-
-        virtual void Invoke()
-        {
-            (TimerImplMemberTraits<OBJ_PTR>::GetReference(m_objPtr).*
-             m_memPtr)(m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
-        }
-
-        MEM_PTR m_memPtr;
-        OBJ_PTR m_objPtr;
-        T1Stored m_a1;
-        T2Stored m_a2;
-        T3Stored m_a3;
-        T4Stored m_a4;
-        T5Stored m_a5;
-        T6Stored m_a6;
-    }* function = new MemFnTimerImplSix(memPtr, objPtr);
+        std::function<U(Ts...)> m_memPtr;
+        std::tuple<std::remove_cvref_t<Ts>...> m_arguments;
+    }* function = new MemFnTimerImpl(memPtr, objPtr);
 
     return function;
 }
@@ -1080,109 +188,21 @@
  *  Implementation of TimerImpl itself.
  ********************************************************************/
 
-template <typename T1>
+template <typename... Args>
 void
-TimerImpl::SetArgs(T1 a1)
+TimerImpl::SetArgs(Args... args)
 {
-    typedef TimerImplOne<typename TimerTraits<T1>::ParameterType> TimerImplBase;
+    using TimerImplBase = TimerImplX<const std::remove_cvref_t<Args>&...>;
     auto impl = dynamic_cast<TimerImplBase*>(this);
     if (impl == nullptr)
     {
         NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
         return;
     }
-    impl->SetArguments(a1);
+    impl->SetArguments(args...);
 }
 
-template <typename T1, typename T2>
-void
-TimerImpl::SetArgs(T1 a1, T2 a2)
-{
-    typedef TimerImplTwo<typename TimerTraits<T1>::ParameterType,
-                         typename TimerTraits<T2>::ParameterType>
-        TimerImplBase;
-    auto impl = dynamic_cast<TimerImplBase*>(this);
-    if (impl == nullptr)
-    {
-        NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
-        return;
-    }
-    impl->SetArguments(a1, a2);
-}
-
-template <typename T1, typename T2, typename T3>
-void
-TimerImpl::SetArgs(T1 a1, T2 a2, T3 a3)
-{
-    typedef TimerImplThree<typename TimerTraits<T1>::ParameterType,
-                           typename TimerTraits<T2>::ParameterType,
-                           typename TimerTraits<T3>::ParameterType>
-        TimerImplBase;
-    auto impl = dynamic_cast<TimerImplBase*>(this);
-    if (impl == nullptr)
-    {
-        NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
-        return;
-    }
-    impl->SetArguments(a1, a2, a3);
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-void
-TimerImpl::SetArgs(T1 a1, T2 a2, T3 a3, T4 a4)
-{
-    typedef TimerImplFour<typename TimerTraits<T1>::ParameterType,
-                          typename TimerTraits<T2>::ParameterType,
-                          typename TimerTraits<T3>::ParameterType,
-                          typename TimerTraits<T4>::ParameterType>
-        TimerImplBase;
-    auto impl = dynamic_cast<TimerImplBase*>(this);
-    if (impl == nullptr)
-    {
-        NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
-        return;
-    }
-    impl->SetArguments(a1, a2, a3, a4);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-void
-TimerImpl::SetArgs(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
-{
-    typedef TimerImplFive<typename TimerTraits<T1>::ParameterType,
-                          typename TimerTraits<T2>::ParameterType,
-                          typename TimerTraits<T3>::ParameterType,
-                          typename TimerTraits<T4>::ParameterType,
-                          typename TimerTraits<T5>::ParameterType>
-        TimerImplBase;
-    auto impl = dynamic_cast<TimerImplBase*>(this);
-    if (impl == nullptr)
-    {
-        NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
-        return;
-    }
-    impl->SetArguments(a1, a2, a3, a4, a5);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
-void
-TimerImpl::SetArgs(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
-{
-    typedef TimerImplSix<typename TimerTraits<T1>::ParameterType,
-                         typename TimerTraits<T2>::ParameterType,
-                         typename TimerTraits<T3>::ParameterType,
-                         typename TimerTraits<T4>::ParameterType,
-                         typename TimerTraits<T5>::ParameterType,
-                         typename TimerTraits<T6>::ParameterType>
-        TimerImplBase;
-    auto impl = dynamic_cast<TimerImplBase*>(this);
-    if (impl == 0)
-    {
-        NS_FATAL_ERROR("You tried to set Timer arguments incompatible with its function.");
-        return;
-    }
-    impl->SetArguments(a1, a2, a3, a4, a5, a6);
-}
+} // namespace internal
 
 } // namespace ns3
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/trickle-timer.cc ns-3.42/src/core/model/trickle-timer.cc
--- ns-3.41/src/core/model/trickle-timer.cc	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/trickle-timer.cc	2024-05-29 15:29:46.936073000 -0700
@@ -21,6 +21,7 @@
 
 #include "log.h"
 
+#include <bit>
 #include <limits>
 
 namespace ns3
@@ -116,20 +117,7 @@
         return 0;
     }
 
-    // Here we assume that m_ticks is a power of 2.
-    // This could have been way more elegant by using
-    // std::countl_zero() defined in the <bit> header
-    // which is c++20 - so not yet widely available.
-
-    uint64_t ticks = m_ticks;
-    uint8_t doublings = 0;
-    while (ticks != 1)
-    {
-        ticks >>= 1;
-        doublings++;
-    }
-
-    return doublings;
+    return std::countr_zero(m_ticks);
 }
 
 uint16_t
@@ -144,7 +132,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_timerExpiration.IsRunning())
+    if (m_timerExpiration.IsPending())
     {
         return Simulator::GetDelayLeft(m_timerExpiration);
     }
@@ -157,7 +145,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_intervalExpiration.IsRunning())
+    if (m_intervalExpiration.IsPending())
     {
         return Simulator::GetDelayLeft(m_intervalExpiration);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/trickle-timer.h ns-3.42/src/core/model/trickle-timer.h
--- ns-3.41/src/core/model/trickle-timer.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/trickle-timer.h	2024-05-29 15:29:46.936073000 -0700
@@ -33,8 +33,13 @@
 namespace ns3
 {
 
+namespace internal
+{
+
 class TimerImpl;
 
+} // namespace internal
+
 /**
  * \ingroup timer
  * \brief A Trickle Timer following \RFC{6206}.
@@ -230,7 +235,7 @@
      * The timer implementation, which contains the bound callback
      * function and arguments.
      */
-    TimerImpl* m_impl;
+    internal::TimerImpl* m_impl;
 
     /** The future event scheduled to expire the timer. */
     EventId m_timerExpiration;
@@ -265,7 +270,7 @@
 TrickleTimer::SetFunction(FN fn)
 {
     delete m_impl;
-    m_impl = MakeTimerImpl(fn);
+    m_impl = internal::MakeTimerImpl(fn);
 }
 
 template <typename MEM_PTR, typename OBJ_PTR>
@@ -273,7 +278,7 @@
 TrickleTimer::SetFunction(MEM_PTR memPtr, OBJ_PTR objPtr)
 {
     delete m_impl;
-    m_impl = MakeTimerImpl(memPtr, objPtr);
+    m_impl = internal::MakeTimerImpl(memPtr, objPtr);
 }
 
 template <typename... Ts>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/tuple.h ns-3.42/src/core/model/tuple.h
--- ns-3.41/src/core/model/tuple.h	2024-02-09 14:44:07.885789900 -0800
+++ ns-3.42/src/core/model/tuple.h	2024-05-29 15:29:46.936073000 -0700
@@ -57,12 +57,21 @@
     return os;
 }
 
-// Doxygen for this class is auto-generated by
-// utils/print-introspected-doxygen.h
+/**
+ * \ingroup attributes
+ * \defgroup attribute_Tuple Tuple Attribute
+ * AttributeValue implementation for Tuple
+ */
 
 /**
+ * \ingroup attribute_Tuple
+ *
+ * AttributeValue implementation for Tuple.
+ *
  * Hold objects of type std::tuple<Args...>.
  * \tparam Args \explicit The list of AttributeValues to be held by this TupleValue
+ *
+ * \see AttributeValue
  */
 template <class... Args>
 class TupleValue : public AttributeValue
@@ -96,6 +105,8 @@
     result_type Get() const;
     /**
      * Set the stored values.
+     *
+     * \param value The stored value
      */
     void Set(const result_type& value);
 
@@ -110,6 +121,7 @@
      *
      * \tparam T \deduced the type of the given variable (normally, the argument type
      *           of a set method or the type of a data member)
+     * \param [out] value The stored value
      * \return true if the given variable was set
      */
     template <typename T>
@@ -131,6 +143,8 @@
 };
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Create a TupleValue object. Enable to write code like this snippet:
  *
  * \code
@@ -149,6 +163,8 @@
 auto MakeTupleValue(T2 t);
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Checker for attribute values storing tuples.
  */
 class TupleChecker : public AttributeChecker
@@ -163,6 +179,8 @@
 };
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Create a TupleChecker from AttributeCheckers associated with TupleValue elements.
  *
  * \tparam Args \explicit Attribute value types
@@ -174,6 +192,8 @@
 Ptr<const AttributeChecker> MakeTupleChecker(Ts... checkers);
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Create an AttributeAccessor for a class data member of type tuple,
  * or a lone class get functor or set method.
  *
@@ -188,6 +208,8 @@
 Ptr<const AttributeAccessor> MakeTupleAccessor(T1 a1);
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Create an AttributeAccessor using a pair of get functor
  * and set methods from a class.
  *
@@ -343,6 +365,8 @@
 {
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Internal checker class templated to each AttributeChecker
  * for each entry in the tuple.
  */
@@ -418,6 +442,8 @@
 };
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Helper class defining static methods for MakeTupleChecker and MakeTupleAccessor
  * that are called when user specifies the list of AttributeValue types included
  * in a TupleValue type.
@@ -454,6 +480,8 @@
 };
 
 /**
+ * \ingroup attribute_Tuple
+ *
  * Helper class defining static methods for MakeTupleValue, MakeTupleChecker and
  * MakeTupleAccessor that are called when user provides a std::tuple of the
  * AttributeValue types included in a TupleValue type.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/type-id.cc ns-3.42/src/core/model/type-id.cc
--- ns-3.41/src/core/model/type-id.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/type-id.cc	2024-05-29 15:29:46.936073000 -0700
@@ -457,7 +457,8 @@
 IidManager::LookupInformation(uint16_t uid) const
 {
     NS_LOG_FUNCTION(IID << uid);
-    NS_ASSERT(uid <= m_information.size() && uid != 0);
+    NS_ASSERT_MSG(uid <= m_information.size() && uid != 0,
+                  "The uid " << uid << " for this TypeId is invalid");
     NS_LOG_LOGIC(IIDL << m_information[uid - 1].name);
     return const_cast<IidInformation*>(&m_information[uid - 1]);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/unix-fd-reader.cc ns-3.42/src/core/model/unix-fd-reader.cc
--- ns-3.41/src/core/model/unix-fd-reader.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/unix-fd-reader.cc	2024-05-29 15:29:46.936073000 -0700
@@ -93,7 +93,7 @@
     // scheduling a "destroy time" method to make sure the thread exits before
     // proceeding.
     //
-    if (!m_destroyEvent.IsRunning())
+    if (!m_destroyEvent.IsPending())
     {
         // hold a reference to ensure that this object is not
         // deallocated before the destroy-time event fires
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/val-array.h ns-3.42/src/core/model/val-array.h
--- ns-3.41/src/core/model/val-array.h	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/val-array.h	2024-05-29 15:29:46.936073000 -0700
@@ -30,6 +30,11 @@
 {
 
 /**
+ * \defgroup Matrices Classes to do efficient math operations on arrays
+ * \ingroup core
+ */
+
+/**
  * \ingroup Matrices
  *
  * \brief ValArray is a class to efficiently store 3D array. The class is general
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/vector.cc ns-3.42/src/core/model/vector.cc
--- ns-3.41/src/core/model/vector.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/vector.cc	2024-05-29 15:29:46.936073000 -0700
@@ -27,7 +27,7 @@
 
 /**
  * \file
- * \ingroup attribute_Vector
+ * \ingroup geometry
  * ns3::Vector, ns3::Vector2D and ns3::Vector3D attribute value implementations.
  */
 
@@ -201,6 +201,24 @@
     return Vector3D(a.x - b.x, a.y - b.y, a.z - b.z);
 }
 
+Vector3D
+operator*(const Vector3D& a, double b)
+{
+    return Vector3D(a.x * b, a.y * b, a.z * b);
+}
+
+Vector3D
+operator*(double a, const Vector3D& b)
+{
+    return Vector3D(b.x * a, b.y * a, b.z * a);
+}
+
+double
+operator*(const Vector3D& a, const Vector3D& b)
+{
+    return a.x * b.x + a.y * b.y + a.z * b.z;
+}
+
 std::ostream&
 operator<<(std::ostream& os, const Vector2D& vector)
 {
@@ -268,4 +286,22 @@
     return Vector2D(a.x - b.x, a.y - b.y);
 }
 
+Vector2D
+operator*(const Vector2D& a, double b)
+{
+    return Vector2D(a.x * b, a.y * b);
+}
+
+Vector2D
+operator*(double a, const Vector2D& b)
+{
+    return Vector2D(b.x * a, b.y * a);
+}
+
+double
+operator*(const Vector2D& a, const Vector2D& b)
+{
+    return a.x * b.x + a.y * b.y;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/vector.h ns-3.42/src/core/model/vector.h
--- ns-3.41/src/core/model/vector.h	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/vector.h	2024-05-29 15:29:46.936073000 -0700
@@ -172,6 +172,30 @@
      * \returns The vector difference of \pname{a} and \pname{b}.
      */
     friend Vector3D operator-(const Vector3D& a, const Vector3D& b);
+
+    /**
+     * Scalar multiplication operator.
+     * \param [in] a lhs vector.
+     * \param [in] b rhs scalar.
+     * \returns The vector \pname{a} scaled by \pname{b}.
+     */
+    friend Vector3D operator*(const Vector3D& a, double b);
+
+    /**
+     * Scalar multiplication operator.
+     * \param [in] a lhs scalar.
+     * \param [in] b rhs vector.
+     * \returns The vector \pname{b} scaled by \pname{a}.
+     */
+    friend Vector3D operator*(double a, const Vector3D& b);
+
+    /**
+     * Dot product operator.
+     * \param [in] a lhs vector.
+     * \param [in] b rhs vector.
+     * \returns The dot product of \pname{a} and \pname{b}.
+     */
+    friend double operator*(const Vector3D& a, const Vector3D& b);
 };
 
 /**
@@ -301,6 +325,30 @@
      * \returns The vector difference of \pname{a} and \pname{b}.
      */
     friend Vector2D operator-(const Vector2D& a, const Vector2D& b);
+
+    /**
+     * Scalar multiplication operator.
+     * \param [in] a lhs vector.
+     * \param [in] b rhs scalar.
+     * \returns The vector \pname{a} scaled by \pname{b}.
+     */
+    friend Vector2D operator*(const Vector2D& a, double b);
+
+    /**
+     * Scalar multiplication operator.
+     * \param [in] a lhs scalar.
+     * \param [in] b rhs vector.
+     * \returns The vector \pname{b} scaled by \pname{a}.
+     */
+    friend Vector2D operator*(double a, const Vector2D& b);
+
+    /**
+     * Dot product operator.
+     * \param [in] a lhs vector.
+     * \param [in] b rhs vector.
+     * \returns The dot product of \pname{a} and \pname{b}.
+     */
+    friend double operator*(const Vector2D& a, const Vector2D& b);
 };
 
 double CalculateDistance(const Vector3D& a, const Vector3D& b);
@@ -318,47 +366,53 @@
 ATTRIBUTE_HELPER_HEADER(Vector2D);
 
 /**
+ * \ingroup attribute_Vector3D
  * \relates Vector3D
  * Vector alias typedef for compatibility with mobility models
  */
 typedef Vector3D Vector;
 
 /**
+ * \ingroup attribute_Vector3D
  * \relates Vector3D
  * Vector alias typedef for compatibility with mobility models
  */
 typedef Vector3DValue VectorValue;
 
 /**
+ * \ingroup attribute_Vector3D
  * \relates Vector3D
  * Vector alias typedef for compatibility with mobility models
  */
 typedef Vector3DChecker VectorChecker;
 
-// Document these by hand so they go in group attribute_Vector3D
-/**
- * \relates Vector3D
- * \fn ns3::Ptr<const ns3::AttributeAccessor> ns3::MakeVectorAccessor (T1 a1)
- * \copydoc ns3::MakeAccessorHelper(T1)
- * \see AttributeAccessor
- */
-
-/**
- * \relates Vector3D
- * \fn ns3::Ptr<const ns3::AttributeAccessor> ns3::MakeVectorAccessor (T1 a1, T2 a2)
- * \copydoc ns3::MakeAccessorHelper(T1,T2)
- * \see AttributeAccessor
- */
-
 ATTRIBUTE_ACCESSOR_DEFINE(Vector);
 
-/**
- * \relates Vector3D
- * \returns The AttributeChecker.
- * \see AttributeChecker
- */
 Ptr<const AttributeChecker> MakeVectorChecker();
 
 } // namespace ns3
 
+// Document these by hand so they go in group attribute_Vector3D
+
+/*!
+\ingroup attribute_Vector3D
+\fn ns3::Ptr<const ns3::AttributeAccessor> ns3::MakeVectorAccessor (T1 a1)
+\copydoc ns3::MakeAccessorHelper(T1)
+\see AttributeAccessor
+*/
+
+/*!
+\ingroup attribute_Vector3D
+\fn ns3::Ptr<const ns3::AttributeAccessor> ns3::MakeVectorAccessor (T1 a1, T2 a2)
+\copydoc ns3::MakeAccessorHelper(T1,T2)
+\see AttributeAccessor
+*/
+
+/*!
+\ingroup attribute_Vector3D
+\fn ns3::Ptr<const ns3::AttributeChecker> ns3::MakeVectorChecker ()
+\returns The AttributeChecker.
+\see AttributeChecker
+*/
+
 #endif /* NS3_VECTOR_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/version.cache ns-3.42/src/core/model/version.cache
--- ns-3.41/src/core/model/version.cache	2024-02-09 14:46:04.290617700 -0800
+++ ns-3.42/src/core/model/version.cache	2024-05-29 15:30:10.908134200 -0700
@@ -1,10 +1,10 @@
-CLOSEST_TAG = '"ns-3.41"'
-VERSION_COMMIT_HASH = '"ge5039092b"'
+CLOSEST_TAG = '"ns-3.42"'
+VERSION_COMMIT_HASH = '"gab4cce021"'
 VERSION_DIRTY_FLAG = '0'
 VERSION_MAJOR = '3'
-VERSION_MINOR = '41'
+VERSION_MINOR = '42'
 VERSION_PATCH = '0'
 VERSION_RELEASE_CANDIDATE = '""'
-VERSION_TAG = '"ns-3.41"'
+VERSION_TAG = '"ns-3.42"'
 VERSION_TAG_DISTANCE = '0'
 VERSION_BUILD_PROFILE = 'default'
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/warnings.h ns-3.42/src/core/model/warnings.h
--- ns-3.41/src/core/model/warnings.h	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/warnings.h	2024-05-29 15:29:46.940073000 -0700
@@ -21,28 +21,42 @@
 #define NS3_WARNINGS_H
 
 /**
+ * \defgroup warnings Compiler warnings
  * \ingroup core
+ *
+ * Macros useful to silence compiler warnings on selected code parts.
+ */
+
+/**
+ * \ingroup warnings
  * \def NS_WARNING_POP
  * Pops the diagnostic warning list from the stack, restoring it to the previous state.
  * \sa NS_WARNING_PUSH
  */
 
 /**
- * \ingroup core
+ * \ingroup warnings
  * \def NS_WARNING_PUSH
  * Push the diagnostic warning list to the stack, allowing it to be restored later.
  * \sa NS_WARNING_POP
  */
 
 /**
- * \ingroup core
+ * \ingroup warnings
  * \def NS_WARNING_SILENCE_DEPRECATED
  * Silences the "-Wdeprecated-declarations" warnings.
  * \sa NS_WARNING_POP
  */
 
 /**
- * \ingroup core
+ * \ingroup warnings
+ * \def NS_WARNING_SILENCE_MAYBE_UNINITIALIZED
+ * Silences GCC "-Wmaybe-uninitialized" warnings.
+ * \sa NS_WARNING_POP
+ */
+
+/**
+ * \ingroup warnings
  * \def NS_WARNING_PUSH_DEPRECATED
  * Save the current warning list and disables the ones about deprecated functions and classes.
  *
@@ -55,9 +69,30 @@
  *   NS_WARNING_POP;
  * \endcode
  *
+ * This macro is equivalent to
+ * \code
+ *   NS_WARNING_PUSH;
+ *   NS_WARNING_SILENCE_DEPRECATED;
+ * \endcode
+ *
  * Its use is, of course, not suggested unless strictly necessary.
  */
 
+/**
+ * \ingroup warnings
+ * \def NS_WARNING_PUSH_MAYBE_UNINITIALIZED
+ * Save the current warning list and disables the ones about possible uninitialized variables.
+ *
+ *
+ * This macro is equivalent to
+ * \code
+ *   NS_WARNING_PUSH;
+ *   NS_WARNING_SILENCE_MAYBE_UNINITIALIZED;
+ * \endcode
+ *
+ * \sa NS_WARNING_PUSH_DEPRECATED
+ */
+
 #if defined(_MSC_VER)
 // You can find the MSC warning codes at
 // https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-c4000-c5999
@@ -79,8 +114,20 @@
 
 #endif
 
+// GCC-specific - Apple's clang pretends to be both...
+#if defined(__GNUC__) && !defined(__clang__)
+#define NS_WARNING_SILENCE_MAYBE_UNINITIALIZED                                                     \
+    _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+#else
+#define NS_WARNING_SILENCE_MAYBE_UNINITIALIZED
+#endif
+
 #define NS_WARNING_PUSH_DEPRECATED                                                                 \
     NS_WARNING_PUSH;                                                                               \
     NS_WARNING_SILENCE_DEPRECATED
 
+#define NS_WARNING_PUSH_MAYBE_UNINITIALIZED                                                        \
+    NS_WARNING_PUSH;                                                                               \
+    NS_WARNING_SILENCE_MAYBE_UNINITIALIZED
+
 #endif /* NS3_WARNINGS_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/watchdog.cc ns-3.42/src/core/model/watchdog.cc
--- ns-3.41/src/core/model/watchdog.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/watchdog.cc	2024-05-29 15:29:46.940073000 -0700
@@ -52,7 +52,7 @@
     NS_LOG_FUNCTION(this << delay);
     Time end = Simulator::Now() + delay;
     m_end = std::max(m_end, end);
-    if (m_event.IsRunning())
+    if (m_event.IsPending())
     {
         return;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/watchdog.h ns-3.42/src/core/model/watchdog.h
--- ns-3.41/src/core/model/watchdog.h	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/watchdog.h	2024-05-29 15:29:46.940073000 -0700
@@ -31,8 +31,13 @@
 namespace ns3
 {
 
+namespace internal
+{
+
 class TimerImpl;
 
+} // namespace internal
+
 /**
  * \ingroup timer
  * \brief A very simple watchdog operating in virtual time.
@@ -115,7 +120,7 @@
      * The timer implementation, which contains the bound callback
      * function and arguments.
      */
-    TimerImpl* m_impl;
+    internal::TimerImpl* m_impl;
     /** The future event scheduled to expire the timer. */
     EventId m_event;
     /** The absolute time when the timer will expire. */
@@ -138,7 +143,7 @@
 Watchdog::SetFunction(FN fn)
 {
     delete m_impl;
-    m_impl = MakeTimerImpl(fn);
+    m_impl = internal::MakeTimerImpl(fn);
 }
 
 template <typename MEM_PTR, typename OBJ_PTR>
@@ -146,7 +151,7 @@
 Watchdog::SetFunction(MEM_PTR memPtr, OBJ_PTR objPtr)
 {
     delete m_impl;
-    m_impl = MakeTimerImpl(memPtr, objPtr);
+    m_impl = internal::MakeTimerImpl(memPtr, objPtr);
 }
 
 template <typename... Ts>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/model/win32-fd-reader.cc ns-3.42/src/core/model/win32-fd-reader.cc
--- ns-3.41/src/core/model/win32-fd-reader.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/model/win32-fd-reader.cc	2024-05-29 15:29:46.940073000 -0700
@@ -41,7 +41,10 @@
 
 NS_LOG_COMPONENT_DEFINE("FdReader");
 
+// conditional compilation to avoid Doxygen errors
+#ifdef __WIN32__
 bool FdReader::winsock_initialized = false;
+#endif
 
 FdReader::FdReader()
     : m_fd(-1),
@@ -101,7 +104,7 @@
     // scheduling a "destroy time" method to make sure the thread exits before
     // proceeding.
     //
-    if (!m_destroyEvent.IsRunning())
+    if (!m_destroyEvent.IsPending())
     {
         // hold a reference to ensure that this object is not
         // deallocated before the destroy-time event fires
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/attribute-container-test-suite.cc ns-3.42/src/core/test/attribute-container-test-suite.cc
--- ns-3.41/src/core/test/attribute-container-test-suite.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/test/attribute-container-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -196,22 +196,6 @@
 /**
  * \ingroup attribute-tests
  *
- * This function handles mixed constness and compatible, yet
- * distinct numerical classes (like int and long)
- * \param x The left operand.
- * \param y The right operand.
- * \return true if the pairs have the same numerical values.
- */
-template <class A, class B, class C, class D>
-bool
-operator==(const std::pair<A, B>& x, const std::pair<C, D>& y)
-{
-    return x.first == y.first && x.second == y.second;
-}
-
-/**
- * \ingroup attribute-tests
- *
  * Test AttributeContainer instantiation, initialization, access
  */
 class AttributeContainerTestCase : public TestCase
@@ -307,7 +291,9 @@
         for (const auto& v : ref)
         {
             NS_TEST_ASSERT_MSG_NE(true, (aciter == ac.End()), "AC iterator reached end");
-            NS_TEST_ASSERT_MSG_EQ(v, (*aciter)->Get(), "Incorrect value");
+            bool valCheck =
+                v.first == (*aciter)->Get().first && v.second == (*aciter)->Get().second;
+            NS_TEST_ASSERT_MSG_EQ(valCheck, true, "Incorrect value");
             ++aciter;
         }
         NS_TEST_ASSERT_MSG_EQ(true, (aciter == ac.End()), "AC iterator did not reach end");
@@ -542,7 +528,8 @@
         auto iter = map.begin();
         for (const auto& v : mapstrint)
         {
-            NS_TEST_ASSERT_MSG_EQ(v, *iter, "Incorrect value in mapstrint");
+            bool valCheck = v.first == (*iter).first && v.second == (*iter).second;
+            NS_TEST_ASSERT_MSG_EQ(valCheck, true, "Incorrect value in mapstrint");
             ++iter;
         }
     }
@@ -560,11 +547,11 @@
 };
 
 AttributeContainerTestSuite::AttributeContainerTestSuite()
-    : TestSuite("attribute-container-test-suite", UNIT)
+    : TestSuite("attribute-container-test-suite", Type::UNIT)
 {
-    AddTestCase(new AttributeContainerTestCase(), TestCase::QUICK);
-    AddTestCase(new AttributeContainerSerializationTestCase(), TestCase::QUICK);
-    AddTestCase(new AttributeContainerSetGetTestCase(), TestCase::QUICK);
+    AddTestCase(new AttributeContainerTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new AttributeContainerSerializationTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new AttributeContainerSetGetTestCase(), TestCase::Duration::QUICK);
 }
 
 static AttributeContainerTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/attribute-test-suite.cc ns-3.42/src/core/test/attribute-test-suite.cc
--- ns-3.41/src/core/test/attribute-test-suite.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/test/attribute-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -2084,44 +2084,44 @@
 };
 
 AttributesTestSuite::AttributesTestSuite()
-    : TestSuite("attributes", UNIT)
+    : TestSuite("attributes", Type::UNIT)
 {
     AddTestCase(new AttributeTestCase<BooleanValue>("Check Attributes of type BooleanValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new AttributeTestCase<IntegerValue>("Check Attributes of type IntegerValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new AttributeTestCase<UintegerValue>("Check Attributes of type UintegerValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new AttributeTestCase<DoubleValue>("Check Attributes of type DoubleValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new AttributeTestCase<EnumValue<AttributeObjectTest::Test_e>>(
                     "Check Attributes of type EnumValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new AttributeTestCase<EnumValue<AttributeObjectTest::Test_ec>>(
                     "Check Attributes of type EnumValue (wrapping an enum class)"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new AttributeTestCase<TimeValue>("Check Attributes of type TimeValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new RandomVariableStreamAttributeTestCase("Check Attributes of type RandomVariableStream"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new ObjectVectorAttributeTestCase("Check Attributes of type ObjectVectorValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ObjectMapAttributeTestCase("Check Attributes of type ObjectMapValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new PointerAttributeTestCase("Check Attributes of type PointerValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new CallbackValueTestCase("Check Attributes of type CallbackValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new IntegerTraceSourceAttributeTestCase(
                     "Ensure TracedValue<uint8_t> can be set like IntegerValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new IntegerTraceSourceTestCase("Ensure TracedValue<uint8_t> also works as trace source"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TracedCallbackTestCase(
                     "Ensure TracedCallback<double, int, float> works as trace source"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 static AttributesTestSuite g_attributesTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/callback-test-suite.cc ns-3.42/src/core/test/callback-test-suite.cc
--- ns-3.41/src/core/test/callback-test-suite.cc	2024-02-09 14:44:07.889790000 -0800
+++ ns-3.42/src/core/test/callback-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -1190,14 +1190,14 @@
 };
 
 CallbackTestSuite::CallbackTestSuite()
-    : TestSuite("callback", UNIT)
+    : TestSuite("callback", Type::UNIT)
 {
-    AddTestCase(new BasicCallbackTestCase, TestCase::QUICK);
-    AddTestCase(new MakeCallbackTestCase, TestCase::QUICK);
-    AddTestCase(new MakeBoundCallbackTestCase, TestCase::QUICK);
-    AddTestCase(new CallbackEqualityTestCase, TestCase::QUICK);
-    AddTestCase(new NullifyCallbackTestCase, TestCase::QUICK);
-    AddTestCase(new MakeCallbackTemplatesTestCase, TestCase::QUICK);
+    AddTestCase(new BasicCallbackTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new MakeCallbackTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new MakeBoundCallbackTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CallbackEqualityTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new NullifyCallbackTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new MakeCallbackTemplatesTestCase, TestCase::Duration::QUICK);
 }
 
 static CallbackTestSuite g_gallbackTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/event-garbage-collector-test-suite.cc ns-3.42/src/core/test/event-garbage-collector-test-suite.cc
--- ns-3.41/src/core/test/event-garbage-collector-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/event-garbage-collector-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -24,7 +24,7 @@
  * \file
  * \ingroup core-tests
  * \ingroup events
- * \ingroup events-garbage-tests
+ * \ingroup event-garbage-tests
  * EventGarbageCollector test suite.
  */
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/examples-as-tests-test-suite.cc ns-3.42/src/core/test/examples-as-tests-test-suite.cc
--- ns-3.41/src/core/test/examples-as-tests-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/examples-as-tests-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -32,6 +32,7 @@
 
 /**
  * \ingroup core-tests
+ * \ingroup testing
  * \defgroup examples-as-tests Examples as tests test suite
  *
  * Runs several examples as tests in order to test ExampleAsTestSuite and ExampleAsTestCase.
@@ -101,7 +102,7 @@
 };
 
 ExamplesAsTestsTestSuite::ExamplesAsTestsTestSuite()
-    : TestSuite("examples-as-tests-test-suite", UNIT)
+    : TestSuite("examples-as-tests-test-suite", Type::UNIT)
 {
     AddTestCase(
         new ExampleAsTestCase("core-example-simulator", "sample-simulator", NS_TEST_SOURCEDIR));
@@ -114,14 +115,14 @@
 }
 
 /**
- * \ingroup examples-tests
+ * \ingroup examples-as-tests
  * ExampleAsTestsTestSuite instance variable.
  * Tests multiple examples in a single TestSuite using AddTestCase to add the examples to the suite.
  */
 static ExamplesAsTestsTestSuite g_examplesAsTestsTestSuite;
 
 /**
- * \ingroup examples-tests
+ * \ingroup examples-as-tests
  * ExampleTestSuite instance variables.
  *
  * Tests ExampleTestSuite which runs a single example as test suite as specified in constructor
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/int64x64-test-suite.cc ns-3.42/src/core/test/int64x64-test-suite.cc
--- ns-3.41/src/core/test/int64x64-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/int64x64-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -575,6 +575,35 @@
 
     // Check special values
     Check(51, int64x64_t(0, 0x159fa87f8aeaad21ULL) * 10, int64x64_t(0, 0xd83c94fb6d2ac34aULL));
+    {
+        auto x = int64x64_t(std::numeric_limits<int64_t>::min(), 0);
+        Check(52, x * 1, x);
+        Check(53, 1 * x, x);
+    }
+    {
+        int64x64_t x(1 << 30, (static_cast<uint64_t>(1) << 63) + 1);
+        auto ret = x * x;
+        int64x64_t expected(1152921505680588800, 4611686020574871553);
+        // The real difference between ret and expected is 2^-128.
+        int64x64_t tolerance = 0;
+        if (int64x64_t::implementation == int64x64_t::ld_impl)
+        {
+            tolerance = tol1;
+        }
+        Check(54, ret, expected, tolerance);
+    }
+
+    // The following triggers an assert in int64x64-128.cc:Umul():117
+    /*
+    {
+        auto x = int64x64_t(1LL << 31);   // 2^31
+        auto y = 2 * x;                   // 2^32
+        Check(55, x, x);
+        Check(56, y, y);
+        auto z [[maybe_unused]] = x * y;  // 2^63 < 0, triggers assert
+        Check(57, z, z);
+    }
+    */
 }
 
 /**
@@ -1557,20 +1586,20 @@
 {
   public:
     Int64x64TestSuite()
-        : TestSuite("int64x64", UNIT)
+        : TestSuite("int64x64", Type::UNIT)
     {
-        AddTestCase(new Int64x64ImplTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64HiLoTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64IntRoundTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64ArithmeticTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64CompareTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64InputTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64InputOutputTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64Bug455TestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64Bug863TestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64Bug1786TestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64InvertTestCase(), TestCase::QUICK);
-        AddTestCase(new Int64x64DoubleTestCase(), TestCase::QUICK);
+        AddTestCase(new Int64x64ImplTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64HiLoTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64IntRoundTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64ArithmeticTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64CompareTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64InputTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64InputOutputTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64Bug455TestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64Bug863TestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64Bug1786TestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64InvertTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Int64x64DoubleTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/length-test-suite.cc ns-3.42/src/core/test/length-test-suite.cc
--- ns-3.41/src/core/test/length-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/length-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -1605,8 +1605,8 @@
 LengthTestSuite::LengthTestSuite()
     : TestSuite("length")
 {
-    AddTestCase(new LengthTestCase(), TestCase::QUICK);
-    AddTestCase(new LengthValueTestCase(), TestCase::QUICK);
+    AddTestCase(new LengthTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new LengthValueTestCase(), TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/many-uniform-random-variables-one-get-value-call-test-suite.cc ns-3.42/src/core/test/many-uniform-random-variables-one-get-value-call-test-suite.cc
--- ns-3.41/src/core/test/many-uniform-random-variables-one-get-value-call-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/many-uniform-random-variables-one-get-value-call-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -28,7 +28,7 @@
  * \file
  * \ingroup core-tests
  * \ingroup randomvariable
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * Test for many uniform random variable streams.
  */
 
@@ -39,15 +39,13 @@
 {
 
 /**
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * Test case for many uniform distribution random variable stream generators
  */
 class ManyUniformRandomVariablesOneGetValueCallTestCase : public TestCase
 {
   public:
-    /** Constructor. */
     ManyUniformRandomVariablesOneGetValueCallTestCase();
-    /** Destructor. */
     ~ManyUniformRandomVariablesOneGetValueCallTestCase() override;
 
   private:
@@ -89,25 +87,24 @@
 }
 
 /**
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * Test suite for many uniform distribution random variable stream generators
  */
 class ManyUniformRandomVariablesOneGetValueCallTestSuite : public TestSuite
 {
   public:
-    /** Constructor. */
     ManyUniformRandomVariablesOneGetValueCallTestSuite();
 };
 
 ManyUniformRandomVariablesOneGetValueCallTestSuite::
     ManyUniformRandomVariablesOneGetValueCallTestSuite()
-    : TestSuite("many-uniform-random-variables-one-get-value-call", PERFORMANCE)
+    : TestSuite("many-uniform-random-variables-one-get-value-call", Type::PERFORMANCE)
 {
     AddTestCase(new ManyUniformRandomVariablesOneGetValueCallTestCase);
 }
 
 /**
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * ManuUniformRandomVariablesOneGetValueCallTestSuite instance variable.
  */
 static ManyUniformRandomVariablesOneGetValueCallTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/matrix-array-test-suite.cc ns-3.42/src/core/test/matrix-array-test-suite.cc
--- ns-3.41/src/core/test/matrix-array-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/matrix-array-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -22,9 +22,13 @@
 #include "ns3/test.h"
 
 /**
- * \file
+ * \defgroup matrixArray-tests MatrixArray tests
  * \ingroup core-tests
- * \ingroup matrixArray
+ * \ingroup Matrices
+ */
+
+/**
+ * \file
  * \ingroup matrixArray-tests
  * MatrixArray test suite
  */
@@ -37,6 +41,27 @@
 NS_LOG_COMPONENT_DEFINE("MatrixArrayTest");
 
 /**
+ * \brief Function casts an input valArray "in" (type IN) to an output valArray "out" (type T)
+ * \param in Input valarray to be casted
+ * \param out Output valarray to receive casted values
+ */
+template <typename IN, typename T>
+void
+CastStdValarray(const std::valarray<IN>& in, std::valarray<T>& out)
+{
+    // Ensure output valarray is the right size
+    if (out.size() != in.size())
+    {
+        out.resize(in.size());
+    }
+
+    // Perform the cast operation
+    std::transform(std::begin(in), std::end(in), std::begin(out), [](IN i) {
+        return static_cast<T>(i);
+    });
+}
+
+/**
  * \ingroup matrixArray-tests
  *  MatrixArray test case for testing constructors, operators and other functions
  */
@@ -439,6 +464,154 @@
     MatrixArray<T> m27 = MatrixArray<T>(std::move(jCasted));
     NS_LOG_INFO("m27.GetSize ()" << m27.GetSize());
     NS_TEST_ASSERT_MSG_EQ(jCastedSize, m27.GetSize(), "The number of elements are not equal.");
+
+    // test determinant
+    {
+        std::vector<std::pair<std::valarray<int>, T>> detTestCases{
+            // right-wraparound
+            {{1, 0, 7, 4, 2, 0, 6, 5, 3}, 62},
+            // left-wraparound
+            {{1, 4, 6, 0, 2, 5, 7, 0, 3}, 62},
+            // identity rank 3
+            {{1, 0, 0, 0, 1, 0, 0, 0, 1}, 1},
+            // identity rank 4
+            {{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, 1},
+            // permutation matrix rank 4
+            {{0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}, -1},
+            // positive det matrix rank 2
+            {{36, -5, -5, 43}, 1523},
+            // single value matrix rank 1
+            {{1}, 1},
+        };
+        for (const auto& [detVal, detRef] : detTestCases)
+        {
+            std::valarray<T> detCast(detVal.size());
+            CastStdValarray(detVal, detCast);
+            auto side = sqrt(detVal.size());
+            MatrixArray<T> detMat = MatrixArray<T>(side, side, std::move(detCast));
+            NS_TEST_ASSERT_MSG_EQ(detMat.Determinant()(0),
+                                  static_cast<T>(detRef),
+                                  "The determinants are not equal.");
+        }
+    }
+    // clang-format off
+    std::valarray<int> multiPageMatrixValues{
+            // page 0: identity matrix
+            1, 0, 0,
+            0, 1, 0,
+            0, 0, 1,
+            // page 1: permutation matrix
+            0, 0, 1,
+            0, 1, 0,
+            1, 0, 0,
+            // page 2: random matrix
+            1, 4, 6,
+            0, 2, 5,
+            7, 0, 3,
+            // page 3: upper triangular
+            5, -9, 2,
+            0, -4, -10,
+            0, 0, -3,
+            // page 4: lower triangular
+            -7, 0, 0,
+            -1, -9, 0,
+            -5, 6, -5,
+            // page 5: zero diagonal
+            0, 1, 2,
+            1, 0, 1,
+            2, 1, 0,
+            // page 6: zero bidiagonal
+            0, 1, 0,
+            1, 0, 1,
+            0, 1, 0
+    };
+    // clang-format on
+    std::valarray<T> castMultiPageMatrixValues(multiPageMatrixValues.size());
+    CastStdValarray(multiPageMatrixValues, castMultiPageMatrixValues);
+    MatrixArray<T> multiPageMatrix = MatrixArray<T>(3,
+                                                    3,
+                                                    multiPageMatrixValues.size() / 9,
+                                                    std::move(castMultiPageMatrixValues));
+    // test the determinant in a multi-page MatrixArray
+    std::vector<int> determinants = {1, -1, 62, 60, -315, 4, 0};
+    auto det = multiPageMatrix.Determinant();
+    for (size_t page = 0; page < multiPageMatrix.GetNumPages(); page++)
+    {
+        NS_TEST_ASSERT_MSG_EQ(det(page),
+                              static_cast<T>(determinants[page]),
+                              "The determinants from the page " << std::to_string(page)
+                                                                << " are not equal.");
+    }
+
+    // test Frobenius norm in a multi-page MatrixArray
+    std::vector<double> fnorms = {sqrt(3), sqrt(3), 11.8322, 15.3297, 14.7309, 3.4641, 2};
+    auto frob = multiPageMatrix.FrobeniusNorm();
+    for (size_t page = 0; page < multiPageMatrix.GetNumPages(); page++)
+    {
+        NS_TEST_ASSERT_MSG_EQ_TOL(std::abs(frob(page)),
+                                  std::abs(static_cast<T>(fnorms[page])),
+                                  0.0001,
+                                  "The Frobenius norm from the page " << std::to_string(page)
+                                                                      << " are not equal.");
+    }
+
+    // test page copying
+    for (size_t noOfCopies = 1; noOfCopies < 4; noOfCopies++)
+    {
+        auto copies = m27.MakeNCopies(noOfCopies);
+        NS_TEST_ASSERT_MSG_EQ(copies.GetNumPages(),
+                              noOfCopies,
+                              "Creating " << std::to_string(noOfCopies) << " copies failed.");
+        NS_TEST_ASSERT_MSG_EQ(copies.GetNumRows(),
+                              m27.GetNumRows(),
+                              "The copy doesn't have the same number of rows as the original.");
+        NS_TEST_ASSERT_MSG_EQ(copies.GetNumCols(),
+                              m27.GetNumCols(),
+                              "The copy doesn't have the same number of columns as the original.");
+        for (size_t page = 0; page < copies.GetNumPages(); page++)
+        {
+            T diff{};
+            for (size_t row = 0; row < copies.GetNumRows(); row++)
+            {
+                for (size_t col = 0; col < copies.GetNumCols(); col++)
+                {
+                    diff += m27(row, col, 0) - copies(row, col, page);
+                }
+            }
+            NS_TEST_ASSERT_MSG_EQ(diff, T{}, "Mismatch in copied values.");
+        }
+    }
+
+    // test page 1 and 0 extraction
+    std::vector<MatrixArray<T>> pages{multiPageMatrix.ExtractPage(1),
+                                      multiPageMatrix.ExtractPage(0)};
+
+    // test page 1 and 0 joining
+    auto jointPagesMatrix = MatrixArray<T>::JoinPages(pages);
+    NS_TEST_ASSERT_MSG_EQ(jointPagesMatrix.GetNumPages(), 2, "Mismatch in number of join pages.");
+    for (size_t page = 0; page < jointPagesMatrix.GetNumPages(); page++)
+    {
+        T diff{};
+        for (size_t row = 0; row < jointPagesMatrix.GetNumRows(); row++)
+        {
+            for (size_t col = 0; col < jointPagesMatrix.GetNumCols(); col++)
+            {
+                diff += multiPageMatrix(row, col, 1 - page) - jointPagesMatrix(row, col, page);
+            }
+        }
+        NS_TEST_ASSERT_MSG_EQ(diff, T{}, "Mismatching pages.");
+    }
+
+    // test identity matrix
+    auto identityRank3Reference = multiPageMatrix.ExtractPage(0);
+    auto identityRank3 = MatrixArray<T>::IdentityMatrix(3);
+    NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
+
+    identityRank3 = MatrixArray<T>::IdentityMatrix(3, 10).ExtractPage(9);
+    NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
+
+    identityRank3 = MatrixArray<T>::IdentityMatrix(identityRank3Reference);
+    NS_TEST_ASSERT_MSG_EQ(identityRank3, identityRank3Reference, "Mismatch in identity matrices.");
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/object-test-suite.cc ns-3.42/src/core/test/object-test-suite.cc
--- ns-3.41/src/core/test/object-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/object-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -466,6 +466,74 @@
 
 /**
  * \ingroup object-tests
+ * Test we can aggregate Objects.
+ */
+class UnidirectionalAggregateObjectTestCase : public TestCase
+{
+  public:
+    /** Constructor. */
+    UnidirectionalAggregateObjectTestCase();
+    /** Destructor. */
+    ~UnidirectionalAggregateObjectTestCase() override;
+
+  private:
+    void DoRun() override;
+};
+
+UnidirectionalAggregateObjectTestCase::UnidirectionalAggregateObjectTestCase()
+    : TestCase("Check Object unidirectional aggregation functionality")
+{
+}
+
+UnidirectionalAggregateObjectTestCase::~UnidirectionalAggregateObjectTestCase()
+{
+}
+
+void
+UnidirectionalAggregateObjectTestCase::DoRun()
+{
+    Ptr<BaseA> baseAOne = CreateObject<BaseA>();
+    NS_TEST_ASSERT_MSG_NE(baseAOne, nullptr, "Unable to CreateObject<BaseA>");
+    Ptr<BaseA> baseATwo = CreateObject<BaseA>();
+    NS_TEST_ASSERT_MSG_NE(baseATwo, nullptr, "Unable to CreateObject<BaseA>");
+
+    Ptr<BaseB> baseB = CreateObject<BaseB>();
+    NS_TEST_ASSERT_MSG_NE(baseB, nullptr, "Unable to CreateObject<BaseB>");
+
+    //
+    // Make an unidirectional aggregation of a BaseA object and a BaseB object.
+    //
+    baseAOne->UnidirectionalAggregateObject(baseB);
+    baseATwo->UnidirectionalAggregateObject(baseB);
+
+    //
+    // We should be able to ask the aggregation (through baseA) for the BaseB part
+    // on either BaseA objects
+    //
+    NS_TEST_ASSERT_MSG_NE(baseAOne->GetObject<BaseB>(),
+                          nullptr,
+                          "Cannot GetObject (through baseAOne) for BaseB Object");
+
+    NS_TEST_ASSERT_MSG_NE(baseATwo->GetObject<BaseB>(),
+                          nullptr,
+                          "Cannot GetObject (through baseATwo) for BaseB Object");
+
+    NS_TEST_ASSERT_MSG_EQ(
+        baseAOne->GetObject<BaseB>(),
+        baseATwo->GetObject<BaseB>(),
+        "GetObject (through baseAOne and baseATwo) for BaseB Object are not equal");
+
+    //
+    // We should not be able to ask the aggregation (through baseB) for the BaseA part
+    // of the aggregation.
+    //
+    NS_TEST_ASSERT_MSG_NE(!baseB->GetObject<BaseA>(),
+                          0,
+                          "Can GetObject (through baseB) for BaseA Object");
+}
+
+/**
+ * \ingroup object-tests
  * Test an Object factory can create Objects
  */
 class ObjectFactoryTestCase : public TestCase
@@ -565,6 +633,7 @@
 {
     AddTestCase(new CreateObjectTestCase);
     AddTestCase(new AggregateObjectTestCase);
+    AddTestCase(new UnidirectionalAggregateObjectTestCase);
     AddTestCase(new ObjectFactoryTestCase);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/one-uniform-random-variable-many-get-value-calls-test-suite.cc ns-3.42/src/core/test/one-uniform-random-variable-many-get-value-calls-test-suite.cc
--- ns-3.41/src/core/test/one-uniform-random-variable-many-get-value-calls-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/one-uniform-random-variable-many-get-value-calls-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -28,7 +28,7 @@
  * \file
  * \ingroup core-tests
  * \ingroup randomvariable
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * Test for one uniform random variable stream.
  */
 
@@ -39,15 +39,13 @@
 {
 
 /**
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * Test case for one uniform distribution random variable stream generator
  */
 class OneUniformRandomVariableManyGetValueCallsTestCase : public TestCase
 {
   public:
-    /** Constructor. */
     OneUniformRandomVariableManyGetValueCallsTestCase();
-    /** Destructor. */
     ~OneUniformRandomVariableManyGetValueCallsTestCase() override;
 
   private:
@@ -89,25 +87,24 @@
 }
 
 /**
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * Test suite for one uniform distribution random variable stream generator
  */
 class OneUniformRandomVariableManyGetValueCallsTestSuite : public TestSuite
 {
   public:
-    /** Constructor. */
     OneUniformRandomVariableManyGetValueCallsTestSuite();
 };
 
 OneUniformRandomVariableManyGetValueCallsTestSuite::
     OneUniformRandomVariableManyGetValueCallsTestSuite()
-    : TestSuite("one-uniform-random-variable-many-get-value-calls", PERFORMANCE)
+    : TestSuite("one-uniform-random-variable-many-get-value-calls", Type::PERFORMANCE)
 {
     AddTestCase(new OneUniformRandomVariableManyGetValueCallsTestCase);
 }
 
 /**
- * \ingroup randomvariable-tests
+ * \ingroup rng-tests
  * OneUniformRandomVariableManyGetValueCallsTestSuite instance variable.
  */
 static OneUniformRandomVariableManyGetValueCallsTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/pair-value-test-suite.cc ns-3.42/src/core/test/pair-value-test-suite.cc
--- ns-3.41/src/core/test/pair-value-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/pair-value-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -211,10 +211,10 @@
 };
 
 PairValueTestSuite::PairValueTestSuite()
-    : TestSuite("pair-value-test-suite", UNIT)
+    : TestSuite("pair-value-test-suite", Type::UNIT)
 {
-    AddTestCase(new PairValueTestCase(), TestCase::QUICK);
-    AddTestCase(new PairValueSettingsTestCase(), TestCase::QUICK);
+    AddTestCase(new PairValueTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new PairValueSettingsTestCase(), TestCase::Duration::QUICK);
 }
 
 static PairValueTestSuite g_pairValueTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/random-variable-stream-test-suite.cc ns-3.42/src/core/test/random-variable-stream-test-suite.cc
--- ns-3.41/src/core/test/random-variable-stream-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/random-variable-stream-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -26,6 +26,7 @@
 #include "ns3/log.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/rng-seed-manager.h"
+#include "ns3/shuffle.h"
 #include "ns3/string.h"
 #include "ns3/test.h"
 
@@ -2873,6 +2874,71 @@
 }
 
 /**
+ * \ingroup rng-test
+ * \ingroup tests
+ *
+ * \brief Test the Shuffle function
+ *
+ * Check that the Shuffle function actually shuffles the elements and does so in a portable way.
+ */
+class ShuffleElementsTest : public TestCase
+{
+  public:
+    ShuffleElementsTest();
+
+  private:
+    void DoRun() override;
+};
+
+ShuffleElementsTest::ShuffleElementsTest()
+    : TestCase("Check correct operation of the Shuffle function")
+{
+}
+
+void
+ShuffleElementsTest::DoRun()
+{
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(1);
+
+    auto rv = CreateObject<UniformRandomVariable>();
+    rv->SetStream(1);
+
+    // test empty vector
+    std::vector<uint8_t> vec{};
+
+    Shuffle(vec.begin(), vec.end(), rv);
+
+    NS_TEST_EXPECT_MSG_EQ(vec.empty(), true, "Expected an empty vector");
+
+    // test vector with one value
+    vec.push_back(3);
+
+    Shuffle(vec.begin(), vec.end(), rv);
+
+    NS_TEST_EXPECT_MSG_EQ((vec == std::vector<uint8_t>{3}), true, "Expected vector {3}");
+
+    // test vector with two values
+    vec.push_back(1);
+
+    Shuffle(vec.begin(), vec.end(), rv);
+
+    NS_TEST_EXPECT_MSG_EQ((vec == std::vector<uint8_t>{1, 3}), true, "Expected vector {1, 3}");
+
+    // test vector with multiple values
+    vec.push_back(7);
+    vec.push_back(2);
+    vec.push_back(4);
+    vec.push_back(9);
+
+    Shuffle(vec.begin(), vec.end(), rv);
+
+    NS_TEST_EXPECT_MSG_EQ((vec == std::vector<uint8_t>{4, 1, 9, 3, 2, 7}),
+                          true,
+                          "Expected vector {4, 1, 9, 3, 2, 7}");
+}
+
+/**
  * \ingroup rng-tests
  * RandomVariableStream test suite, covering all random number variable
  * stream generator types.
@@ -2885,7 +2951,7 @@
 };
 
 RandomVariableSuite::RandomVariableSuite()
-    : TestSuite("random-variable-stream-generators", UNIT)
+    : TestSuite("random-variable-stream-generators", Type::UNIT)
 {
     AddTestCase(new UniformTestCase);
     AddTestCase(new UniformAntitheticTestCase);
@@ -2928,6 +2994,7 @@
     AddTestCase(new BernoulliAntitheticTestCase);
     AddTestCase(new BinomialTestCase);
     AddTestCase(new BinomialAntitheticTestCase);
+    AddTestCase(new ShuffleElementsTest);
 }
 
 static RandomVariableSuite randomVariableSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/rng-test-suite.cc ns-3.42/src/core/test/rng-test-suite.cc
--- ns-3.41/src/core/test/rng-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/rng-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -488,12 +488,12 @@
 };
 
 RngTestSuite::RngTestSuite()
-    : TestSuite("random-number-generators", UNIT)
+    : TestSuite("random-number-generators", Type::UNIT)
 {
-    AddTestCase(new RngUniformTestCase, TestCase::QUICK);
-    AddTestCase(new RngNormalTestCase, TestCase::QUICK);
-    AddTestCase(new RngExponentialTestCase, TestCase::QUICK);
-    AddTestCase(new RngParetoTestCase, TestCase::QUICK);
+    AddTestCase(new RngUniformTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new RngNormalTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new RngExponentialTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new RngParetoTestCase, TestCase::Duration::QUICK);
 }
 
 static RngTestSuite g_rngTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/simulator-test-suite.cc ns-3.42/src/core/test/simulator-test-suite.cc
--- ns-3.41/src/core/test/simulator-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/simulator-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -721,15 +721,15 @@
         ObjectFactory factory;
         factory.SetTypeId(ListScheduler::GetTypeId());
 
-        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::QUICK);
+        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::Duration::QUICK);
         factory.SetTypeId(MapScheduler::GetTypeId());
-        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::QUICK);
+        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::Duration::QUICK);
         factory.SetTypeId(HeapScheduler::GetTypeId());
-        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::QUICK);
+        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::Duration::QUICK);
         factory.SetTypeId(CalendarScheduler::GetTypeId());
-        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::QUICK);
+        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::Duration::QUICK);
         factory.SetTypeId(PriorityQueueScheduler::GetTypeId());
-        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::QUICK);
+        AddTestCase(new SimulatorEventsTestCase(factory), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/threaded-test-suite.cc ns-3.42/src/core/test/threaded-test-suite.cc
--- ns-3.41/src/core/test/threaded-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/threaded-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -311,7 +311,7 @@
                     factory.SetTypeId(schedulerType);
                     AddTestCase(
                         new ThreadedSimulatorEventsTestCase(factory, simulatorType, threadCount),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
                 }
             }
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/timer-test-suite.cc ns-3.42/src/core/test/timer-test-suite.cc
--- ns-3.41/src/core/test/timer-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/timer-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -229,10 +229,10 @@
 {
   public:
     TimerTestSuite()
-        : TestSuite("timer", UNIT)
+        : TestSuite("timer", Type::UNIT)
     {
-        AddTestCase(new TimerStateTestCase(), TestCase::QUICK);
-        AddTestCase(new TimerTemplateTestCase(), TestCase::QUICK);
+        AddTestCase(new TimerStateTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new TimerTemplateTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/time-test-suite.cc ns-3.42/src/core/test/time-test-suite.cc
--- ns-3.41/src/core/test/time-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/time-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -542,12 +542,12 @@
 {
   public:
     TimeTestSuite()
-        : TestSuite("time", UNIT)
+        : TestSuite("time", Type::UNIT)
     {
-        AddTestCase(new TimeWithSignTestCase(), TestCase::QUICK);
-        AddTestCase(new TimeInputOutputTestCase(), TestCase::QUICK);
+        AddTestCase(new TimeWithSignTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new TimeInputOutputTestCase(), TestCase::Duration::QUICK);
         // This should be last, since it changes the resolution
-        AddTestCase(new TimeSimpleTestCase(), TestCase::QUICK);
+        AddTestCase(new TimeSimpleTestCase(), TestCase::Duration::QUICK);
     }
 }
 /** \brief Member variable for time test suite */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/traced-callback-test-suite.cc ns-3.42/src/core/test/traced-callback-test-suite.cc
--- ns-3.41/src/core/test/traced-callback-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/traced-callback-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -145,9 +145,9 @@
 };
 
 TracedCallbackTestSuite::TracedCallbackTestSuite()
-    : TestSuite("traced-callback", UNIT)
+    : TestSuite("traced-callback", Type::UNIT)
 {
-    AddTestCase(new BasicTracedCallbackTestCase, TestCase::QUICK);
+    AddTestCase(new BasicTracedCallbackTestCase, TestCase::Duration::QUICK);
 }
 
 static TracedCallbackTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/trickle-timer-test-suite.cc ns-3.42/src/core/test/trickle-timer-test-suite.cc
--- ns-3.41/src/core/test/trickle-timer-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/trickle-timer-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -142,6 +142,8 @@
                              expirationFrequency.begin());
     expirationFrequency.erase(expirationFrequency.begin());
 
+    NS_TEST_ASSERT_MSG_EQ(expirationFrequency.empty(), false, "No expiration frequency");
+
     int64x64_t min =
         (*std::min_element(expirationFrequency.begin(), expirationFrequency.end())) / unit;
     int64x64_t max =
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/tuple-value-test-suite.cc ns-3.42/src/core/test/tuple-value-test-suite.cc
--- ns-3.41/src/core/test/tuple-value-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/tuple-value-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -321,9 +321,9 @@
 };
 
 TupleValueTestSuite::TupleValueTestSuite()
-    : TestSuite("tuple-value-test-suite", UNIT)
+    : TestSuite("tuple-value-test-suite", Type::UNIT)
 {
-    AddTestCase(new TupleValueTestCase(), TestCase::QUICK);
+    AddTestCase(new TupleValueTestCase(), TestCase::Duration::QUICK);
 }
 
 static TupleValueTestSuite g_tupleValueTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/type-id-test-suite.cc ns-3.42/src/core/test/type-id-test-suite.cc
--- ns-3.41/src/core/test/type-id-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/type-id-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -443,7 +443,7 @@
 };
 
 TypeIdTestSuite::TypeIdTestSuite()
-    : TestSuite("type-id", UNIT)
+    : TestSuite("type-id", Type::UNIT)
 {
     // Turn on logging, so we see the result of collisions
     LogComponentEnable("TypeId", ns3::LogLevel(LOG_ERROR | LOG_PREFIX_FUNC));
@@ -452,9 +452,9 @@
     // UniqueIdTestCase, the artificial collisions added by
     // CollisionTestCase will show up in the list of TypeIds
     // as chained.
-    AddTestCase(new UniqueTypeIdTestCase, QUICK);
-    AddTestCase(new CollisionTestCase, QUICK);
-    AddTestCase(new DeprecatedAttributeTestCase, QUICK);
+    AddTestCase(new UniqueTypeIdTestCase, Duration::QUICK);
+    AddTestCase(new CollisionTestCase, Duration::QUICK);
+    AddTestCase(new DeprecatedAttributeTestCase, Duration::QUICK);
 }
 
 /// Static variable for test initialization.
@@ -472,9 +472,9 @@
 };
 
 TypeIdPerformanceSuite::TypeIdPerformanceSuite()
-    : TestSuite("type-id-perf", PERFORMANCE)
+    : TestSuite("type-id-perf", Type::PERFORMANCE)
 {
-    AddTestCase(new LookupTimeTestCase, QUICK);
+    AddTestCase(new LookupTimeTestCase, Duration::QUICK);
 }
 
 /// Static variable for test initialization.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/core/test/val-array-test-suite.cc ns-3.42/src/core/test/val-array-test-suite.cc
--- ns-3.41/src/core/test/val-array-test-suite.cc	2024-02-09 14:44:07.893790000 -0800
+++ ns-3.42/src/core/test/val-array-test-suite.cc	2024-05-29 15:29:46.940073000 -0700
@@ -22,6 +22,19 @@
 #include "ns3/val-array.h"
 
 /**
+ * \defgroup valArray-tests ValArray tests
+ * \ingroup core-tests
+ * \ingroup Matrices
+ */
+
+/**
+ * \file
+ * \ingroup valArray-tests
+ * ValArray test suite
+ */
+
+/**
+ * \file
  * \ingroup core-tests
  */
 
@@ -33,6 +46,8 @@
 NS_LOG_COMPONENT_DEFINE("ValArrayTest");
 
 /**
+ * @ingroup valArray-tests
+ *
  * @brief ValArray test case for testing ValArray class
  *
  * @tparam T the template parameter that can be a complex number, double or int
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/csma/model/csma-net-device.cc ns-3.42/src/csma/model/csma-net-device.cc
--- ns-3.41/src/csma/model/csma-net-device.cc	2024-02-09 14:44:07.897790000 -0800
+++ ns-3.42/src/csma/model/csma-net-device.cc	2024-05-29 15:29:46.940073000 -0700
@@ -912,7 +912,7 @@
 CsmaNetDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION_NOARGS();
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsdv/examples/dsdv-manet.cc ns-3.42/src/dsdv/examples/dsdv-manet.cc
--- ns-3.41/src/dsdv/examples/dsdv-manet.cc	2024-02-09 14:44:07.897790000 -0800
+++ ns-3.42/src/dsdv/examples/dsdv-manet.cc	2024-05-29 15:29:46.940073000 -0700
@@ -46,9 +46,13 @@
 NS_LOG_COMPONENT_DEFINE("DsdvManetExample");
 
 /**
+ * \defgroup dsdv-examples DSDV Examples
  * \ingroup dsdv
- * \ingroup dsdv-examples
  * \ingroup examples
+ */
+
+/**
+ * \ingroup dsdv-examples
  *
  * \brief DSDV Manet example
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsdv/model/dsdv-rtable.cc ns-3.42/src/dsdv/model/dsdv-rtable.cc
--- ns-3.41/src/dsdv/model/dsdv-rtable.cc	2024-02-09 14:44:07.897790000 -0800
+++ ns-3.42/src/dsdv/model/dsdv-rtable.cc	2024-05-29 15:29:46.944073200 -0700
@@ -312,7 +312,7 @@
         return false;
     }
     event = i->second;
-    return event.IsRunning();
+    return event.IsPending();
 }
 
 bool
@@ -340,7 +340,7 @@
         return false;
     }
     event = i->second;
-    if (event.IsRunning())
+    if (event.IsPending())
     {
         return false;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsdv/test/dsdv-testcase.cc ns-3.42/src/dsdv/test/dsdv-testcase.cc
--- ns-3.41/src/dsdv/test/dsdv-testcase.cc	2024-02-09 14:44:07.897790000 -0800
+++ ns-3.42/src/dsdv/test/dsdv-testcase.cc	2024-05-29 15:29:46.944073200 -0700
@@ -218,9 +218,9 @@
 {
   public:
     DsdvTestSuite()
-        : TestSuite("routing-dsdv", UNIT)
+        : TestSuite("routing-dsdv", Type::UNIT)
     {
-        AddTestCase(new DsdvHeaderTestCase(), TestCase::QUICK);
-        AddTestCase(new DsdvTableTestCase(), TestCase::QUICK);
+        AddTestCase(new DsdvHeaderTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new DsdvTableTestCase(), TestCase::Duration::QUICK);
     }
 } g_dsdvTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/model/dsr-fs-header.cc ns-3.42/src/dsr/model/dsr-fs-header.cc
--- ns-3.41/src/dsr/model/dsr-fs-header.cc	2024-02-09 14:44:07.897790000 -0800
+++ ns-3.42/src/dsr/model/dsr-fs-header.cc	2024-05-29 15:29:46.944073200 -0700
@@ -34,6 +34,8 @@
 #include "ns3/header.h"
 #include "ns3/log.h"
 
+#include <vector>
+
 namespace ns3
 {
 
@@ -174,9 +176,9 @@
     m_destId = i.ReadU16();
     m_payloadLen = i.ReadU16();
 
-    uint32_t dataLength = GetPayloadLength();
-    uint8_t data[dataLength];
-    i.Read(data, dataLength);
+    const uint32_t dataLength = GetPayloadLength();
+    std::vector<uint8_t> data(dataLength);
+    i.Read(data.data(), dataLength);
 
     if (dataLength > m_data.GetSize())
     {
@@ -188,7 +190,7 @@
     }
 
     i = m_data.Begin();
-    i.Write(data, dataLength);
+    i.Write(data.data(), data.size());
 
     return GetSerializedSize();
 }
@@ -233,11 +235,11 @@
 uint32_t
 DsrOptionField::Deserialize(Buffer::Iterator start, uint32_t length)
 {
-    uint8_t buf[length];
-    start.Read(buf, length);
+    std::vector<uint8_t> buf(length);
+    start.Read(buf.data(), length);
     m_optionData = Buffer();
     m_optionData.AddAtEnd(length);
-    m_optionData.Begin().Write(buf, length);
+    m_optionData.Begin().Write(buf.data(), buf.size());
     return length;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/model/dsr-maintain-buff.h ns-3.42/src/dsr/model/dsr-maintain-buff.h
--- ns-3.41/src/dsr/model/dsr-maintain-buff.h	2024-02-09 14:44:07.897790000 -0800
+++ ns-3.42/src/dsr/model/dsr-maintain-buff.h	2024-05-29 15:29:46.944073200 -0700
@@ -477,7 +477,7 @@
 
     /**
      * Set maintain buffer timeout
-     * \param t the maintain buffer timeoout
+     * \param t the maintain buffer timeout
      */
     void SetMaintainBufferTimeout(Time t)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/model/dsr-option-header.h ns-3.42/src/dsr/model/dsr-option-header.h
--- ns-3.41/src/dsr/model/dsr-option-header.h	2024-02-09 14:44:07.901790100 -0800
+++ ns-3.42/src/dsr/model/dsr-option-header.h	2024-05-29 15:29:46.944073200 -0700
@@ -384,7 +384,7 @@
      */
     Ipv4Address m_target;
     /**
-     * Ipv4 address to write when desearizing the packet
+     * Ipv4 address to write when deserializing the packet
      */
     Ipv4Address m_address;
     /**
@@ -673,7 +673,7 @@
 
   private:
     /**
-     * \brief The ip address header deserilize to
+     * \brief The ip address header deserialize to
      */
     Ipv4Address m_address;
     /**
@@ -681,7 +681,7 @@
      */
     uint8_t m_segmentsLeft;
     /**
-     * \brief Number of savlage times for a packet.
+     * \brief Number of salvage times for a packet.
      */
     uint8_t m_salvage;
     /**
@@ -821,7 +821,7 @@
      */
     uint8_t m_errorType;
     /**
-     * \brief The salavage field
+     * \brief The salvage field
      */
     uint8_t m_salvage;
     /**
@@ -976,7 +976,7 @@
      */
     uint8_t m_errorType;
     /**
-     * \brief The salavage field
+     * \brief The salvage field
      */
     uint8_t m_salvage;
     /**
@@ -1122,7 +1122,7 @@
      */
     uint8_t m_errorType;
     /**
-     * \brief The salavage field
+     * \brief The salvage field
      */
     uint8_t m_salvage;
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/model/dsr-rcache.cc ns-3.42/src/dsr/model/dsr-rcache.cc
--- ns-3.41/src/dsr/model/dsr-rcache.cc	2024-02-09 14:44:07.901790100 -0800
+++ ns-3.42/src/dsr/model/dsr-rcache.cc	2024-05-29 15:29:46.944073200 -0700
@@ -799,7 +799,7 @@
         auto i = m_nodeCache.find(errorSrc);
         if (i == m_nodeCache.end())
         {
-            NS_LOG_LOGIC("Update the node stability unsuccessfuly");
+            NS_LOG_LOGIC("Update the node stability unsuccessfully");
         }
         else
         {
@@ -808,7 +808,7 @@
         i = m_nodeCache.find(unreachNode);
         if (i == m_nodeCache.end())
         {
-            NS_LOG_LOGIC("Update the node stability unsuccessfuly");
+            NS_LOG_LOGIC("Update the node stability unsuccessfully");
         }
         else
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/model/dsr-routing.cc ns-3.42/src/dsr/model/dsr-routing.cc
--- ns-3.41/src/dsr/model/dsr-routing.cc	2024-02-09 14:44:07.901790100 -0800
+++ ns-3.42/src/dsr/model/dsr-routing.cc	2024-05-29 15:29:46.944073200 -0700
@@ -136,7 +136,7 @@
             .AddAttribute(
                 "PassiveBuffer",
                 "The passive buffer to manage "
-                "promisucously received passive ack.",
+                "promiscuously received passive ack.",
                 PointerValue(nullptr),
                 MakePointerAccessor(&DsrRouting::SetPassiveBuffer, &DsrRouting::GetPassiveBuffer),
                 MakePointerChecker<DsrPassiveBuffer>())
@@ -1122,7 +1122,7 @@
     /*
      * Message type 2 means the data packet, we will further process the data
      * packet for delivery notification, safely ignore control packet
-     * Another check here is our own address, if this is the data destinated for us,
+     * Another check here is our own address, if this is the data destined for us,
      * process it further, otherwise, just ignore it
      */
     Ipv4Address ourAddress = m_ipv4->GetAddress(1, 0).GetLocal();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/model/dsr-rreq-table.h ns-3.42/src/dsr/model/dsr-rreq-table.h
--- ns-3.41/src/dsr/model/dsr-rreq-table.h	2024-02-09 14:44:07.901790100 -0800
+++ ns-3.42/src/dsr/model/dsr-rreq-table.h	2024-05-29 15:29:46.944073200 -0700
@@ -373,7 +373,7 @@
     Time MaxRequestPeriod;
     /// The original request period
     Time RequestPeriod;
-    /// The non-propagaton request timeout
+    /// The non-propagation request timeout
     Time NonpropRequestTimeout;
     /// The source route entry expire time
     Time m_rreqEntryExpire;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/dsr/test/dsr-test-suite.cc ns-3.42/src/dsr/test/dsr-test-suite.cc
--- ns-3.41/src/dsr/test/dsr-test-suite.cc	2024-02-09 14:44:07.901790100 -0800
+++ ns-3.42/src/dsr/test/dsr-test-suite.cc	2024-05-29 15:29:46.944073200 -0700
@@ -630,16 +630,16 @@
 {
   public:
     DsrTestSuite()
-        : TestSuite("routing-dsr", UNIT)
+        : TestSuite("routing-dsr", Type::UNIT)
     {
-        AddTestCase(new DsrFsHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrRreqHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrRrepHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrSRHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrRerrHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrAckReqHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrAckHeaderTest, TestCase::QUICK);
-        AddTestCase(new DsrCacheEntryTest, TestCase::QUICK);
-        AddTestCase(new DsrSendBuffTest, TestCase::QUICK);
+        AddTestCase(new DsrFsHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrRreqHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrRrepHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrSRHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrRerrHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrAckReqHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrAckHeaderTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrCacheEntryTest, TestCase::Duration::QUICK);
+        AddTestCase(new DsrSendBuffTest, TestCase::Duration::QUICK);
     }
 } g_dsrTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/doc/energy.rst ns-3.42/src/energy/doc/energy.rst
--- ns-3.41/src/energy/doc/energy.rst	2024-02-09 14:44:07.901790100 -0800
+++ ns-3.42/src/energy/doc/energy.rst	2024-05-29 15:29:46.944073200 -0700
@@ -41,7 +41,7 @@
 
 An energy source represents a power supply. In |ns3|, nodes can
 have one or more energy sources. Likewise, energy sources can be
-connected to multiple energy consuption models (Device energy models).
+connected to multiple energy consumption models (Device energy models).
 Connecting an energy source to a device energy model implies that the
 corresponding device draws power from the source.
 When energy is completely drained from the energy source, it notifies to the device energy models on
@@ -67,11 +67,11 @@
 
 The ``EnergySource`` base class keeps a list of devices (``DeviceEnergyModel`` objects) and energy harvesters (``EnergyHarvester`` objects) that are using the particular Energy Source as power supply. When energy is completely drained, the Energy Source will notify all devices on this list. Each device can then handle this event independently, based on the desired behavior that should be followed in case of power outage.
 
-Generic Batttery Model
-######################
+Generic Battery Model
+#####################
 
 The Generic battery model is able to represent 4 basic types of batteries
-chemestries: Lithium-Ion (LiIon) or Lithium Polymer (LiPo), Nickel Cadmium (NiCd),
+chemistries: Lithium-Ion (LiIon) or Lithium Polymer (LiPo), Nickel Cadmium (NiCd),
 Lead Acid, and Nickel-metal hydride (NiMH). The main difference between these batteries
 is the shape of the discharge curves when using constant discharge current and that
 NiCd and NiMh batteries hysteresis phenomenon is also modeled. Peurket effect, aging,
@@ -81,10 +81,10 @@
 
 The Generic Battery Model is directly based by the works of Trembley et al.
 Tremblay's model on itself is based on a popular battery model created by Shepherd.
-Tremblay's model consist in visually identify a set of points from batteries manufacters'
+Tremblay's model consist in visually identify a set of points from batteries manufacturers'
 discharge curves datasheets.
 
-.. _fig-energyFramework:
+.. _fig-dischargeCurve:
 
 .. figure:: figures/dischargeCurve.*
 
@@ -108,7 +108,7 @@
 * :math:`cutoffVoltage:` Required if we desired to inform connected energy consumption models that the battery has reached its discharged point.
 * :math:`i:` The discharge current used to discharge the battery. This value is provided by the energy consumption model attached to the battery.
 
-The value of :math:`R` is typically included in the datatsheets, however, because :math:`R` variability is not modeled in |ns3| (The resistance is fixed), it is necessary
+The value of :math:`R` is typically included in the datasheets, however, because :math:`R` variability is not modeled in |ns3| (The resistance is fixed), it is necessary
 to discretely adjust its value to obtain the desired discharge curves. The value :math:`i_{typical}` can
 be obtained by inferring its value from the discharged curves shown in datasheets. When modeling
 the behavior of a new battery, it is important to chose values that satisfies more than one curve,
@@ -285,7 +285,7 @@
 **Generic Battery Model Helper:**
 
 The ``GenericBatteryModelHelper`` can be used to easily install an energy source into a
-node or node container of one of four types of chemestries (Li-Ion,Lead Acid, NiCd,NiMH).
+node or node container of one of four types of chemistries (Li-Ion,Lead Acid, NiCd,NiMH).
 Users must use one of the available presets that represent an specific battery.
 
 .. sourcecode:: cpp
@@ -395,7 +395,7 @@
 Validation
 **********
 
-The RV battery model is validated by comparing results with what was presented in the original RV battery model paper. The generic battery model is validated by superimposing the obtained discharge curves with manufacters's datasheets plots. The following shows the results of the ``generic-battery-discharge-example.cc`` superimposed to manufacter's datasheets charts:
+The RV battery model is validated by comparing results with what was presented in the original RV battery model paper. The generic battery model is validated by superimposing the obtained discharge curves with manufacturer's datasheets plots. The following shows the results of the ``generic-battery-discharge-example.cc`` superimposed to manufacturer's datasheets charts:
 
 
 .. _fig-leadacid:
@@ -436,7 +436,7 @@
 ===========
 
 * Support of device energy models for PHY layers (lr-wpan, WiMax, etc) and other pieces of hardware (UAV, sensors, CPU).
-* Support for realistical charging batteries in the ``GenericBatteryModule``.
+* Support for realistic charging batteries in the ``GenericBatteryModule``.
 * Support for device capable of charging batteries (e.g. chargers with CCCV capabilities).
 * Implement an energy harvester that recharges the energy sources according to the power levels defined in a user customizable dataset of real measurements.
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/examples/basic-energy-model-test.cc ns-3.42/src/energy/examples/basic-energy-model-test.cc
--- ns-3.41/src/energy/examples/basic-energy-model-test.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/examples/basic-energy-model-test.cc	2024-05-29 15:29:46.948073100 -0700
@@ -34,6 +34,7 @@
 #include <cmath>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("BasicEnergyModelTestSuite");
 
@@ -165,7 +166,10 @@
      */
 
     // schedule change of state
-    Simulator::Schedule(Seconds(m_timeS), &WifiRadioEnergyModel::ChangeState, devModel, state);
+    Simulator::Schedule(Seconds(m_timeS),
+                        &WifiRadioEnergyModel::ChangeState,
+                        devModel,
+                        static_cast<int>(state));
 
     // Calculate remaining energy at simulation stop time
     Simulator::Schedule(Seconds(m_timeS * 2), &BasicEnergySource::UpdateEnergySource, source);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/examples/generic-battery-discharge-example.cc ns-3.42/src/energy/examples/generic-battery-discharge-example.cc
--- ns-3.41/src/energy/examples/generic-battery-discharge-example.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/examples/generic-battery-discharge-example.cc	2024-05-29 15:29:46.948073100 -0700
@@ -26,6 +26,7 @@
 #include <string>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 /**
  * This example shows the use of batteries in ns-3.
@@ -44,8 +45,10 @@
  *
  * Plot files are produced as a result of this example.
  * Graphs can be obtained from the plot using:
+ * \code{.sh}
+   $> gnuplot <plotname>.plt
+   \endcode
  *
- * $> gnuplot <plotname>.plt
  */
 
 Gnuplot battDischPlot1 = Gnuplot("BattDisch1.eps");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/examples/generic-battery-discharge-example.py ns-3.42/src/energy/examples/generic-battery-discharge-example.py
--- ns-3.41/src/energy/examples/generic-battery-discharge-example.py	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/examples/generic-battery-discharge-example.py	2024-05-29 15:29:46.948073100 -0700
@@ -37,27 +37,29 @@
     argv: System parameters to use if necessary
     """
 
-    ns.core.LogComponentEnable("GenericBatteryModel", ns.core.LOG_LEVEL_DEBUG)
+    ns.LogComponentEnable("GenericBatteryModel", ns.LOG_LEVEL_DEBUG)
 
-    node = ns.network.Node()
-    batteryHelper = ns.energy.GenericBatteryModelHelper()
-    batteryModel = ns.CreateObject("GenericBatteryModel")
+    node = ns.Node()
+    batteryHelper = ns.GenericBatteryModelHelper()
+    batteryModel = ns.CreateObject[ns.energy.GenericBatteryModel]()
     devicesEnergyModel = ns.energy.SimpleDeviceEnergyModel()
 
-    batteryModel.SetAttribute("FullVoltage", ns.core.DoubleValue(1.39))  # Vfull
-    batteryModel.SetAttribute("MaxCapacity", ns.core.DoubleValue(7.0))  # Q
+    batteryModel.SetAttribute("FullVoltage", ns.DoubleValue(1.39))  # Vfull
+    batteryModel.SetAttribute("MaxCapacity", ns.DoubleValue(7.0))  # Q
 
-    batteryModel.SetAttribute("NominalVoltage", ns.core.DoubleValue(1.18))  # Vnom
-    batteryModel.SetAttribute("NominalCapacity", ns.core.DoubleValue(6.25))  # QNom
+    batteryModel.SetAttribute("NominalVoltage", ns.DoubleValue(1.18))  # Vnom
+    batteryModel.SetAttribute("NominalCapacity", ns.DoubleValue(6.25))  # QNom
 
-    batteryModel.SetAttribute("ExponentialVoltage", ns.core.DoubleValue(1.28))  # Vexp
-    batteryModel.SetAttribute("ExponentialCapacity", ns.core.DoubleValue(1.3))  # Qexp
+    batteryModel.SetAttribute("ExponentialVoltage", ns.DoubleValue(1.28))  # Vexp
+    batteryModel.SetAttribute("ExponentialCapacity", ns.DoubleValue(1.3))  # Qexp
 
-    batteryModel.SetAttribute("InternalResistance", ns.core.DoubleValue(0.0046))  # R
-    batteryModel.SetAttribute("TypicalDischargeCurrent", ns.core.DoubleValue(1.3))  # i typical
-    batteryModel.SetAttribute("CutoffVoltage", ns.core.DoubleValue(1.0))  # End of charge.
-
-    batteryModel.SetAttribute("BatteryType", ns.core.EnumValue(ns.NIMH_NICD))  # Battery type
+    batteryModel.SetAttribute("InternalResistance", ns.DoubleValue(0.0046))  # R
+    batteryModel.SetAttribute("TypicalDischargeCurrent", ns.DoubleValue(1.3))  # i typical
+    batteryModel.SetAttribute("CutoffVoltage", ns.DoubleValue(1.0))  # End of charge.
+
+    batteryModel.SetAttribute(
+        "BatteryType", ns.EnumValue[ns.energy.GenericBatteryType](ns.energy.NIMH_NICD)
+    )  # Battery type
 
     devicesEnergyModel.SetEnergySource(batteryModel)
     batteryModel.AppendDeviceEnergyModel(devicesEnergyModel)
@@ -65,9 +67,9 @@
 
     devicesEnergyModel.SetCurrentA(6.5)
 
-    ns.core.Simulator.Stop(ns.core.Seconds(3600))
-    ns.core.Simulator.Run()
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Stop(ns.Seconds(3600))
+    ns.Simulator.Run()
+    ns.Simulator.Destroy()
 
 
 if __name__ == "__main__":
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/examples/generic-battery-wifiradio-example.cc ns-3.42/src/energy/examples/generic-battery-wifiradio-example.cc
--- ns-3.41/src/energy/examples/generic-battery-wifiradio-example.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/examples/generic-battery-wifiradio-example.cc	2024-05-29 15:29:46.948073100 -0700
@@ -48,6 +48,7 @@
 #include <string>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("GenericBatteryWifiRadioExample");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/examples/li-ion-energy-source-example.cc ns-3.42/src/energy/examples/li-ion-energy-source-example.cc
--- ns-3.41/src/energy/examples/li-ion-energy-source-example.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/examples/li-ion-energy-source-example.cc	2024-05-29 15:29:46.948073100 -0700
@@ -25,6 +25,7 @@
 #include "ns3/simulator.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 /**
  * In this simple example, we show how to create and drain energy from a
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/examples/rv-battery-model-test.cc ns-3.42/src/energy/examples/rv-battery-model-test.cc
--- ns-3.41/src/energy/examples/rv-battery-model-test.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/examples/rv-battery-model-test.cc	2024-05-29 15:29:46.948073100 -0700
@@ -35,6 +35,7 @@
 #include <cmath>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("RvBatteryModelTestSuite");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/basic-energy-harvester-helper.cc ns-3.42/src/energy/helper/basic-energy-harvester-helper.cc
--- ns-3.41/src/energy/helper/basic-energy-harvester-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/basic-energy-harvester-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -40,14 +40,15 @@
     m_basicEnergyHarvester.Set(name, v);
 }
 
-Ptr<EnergyHarvester>
-BasicEnergyHarvesterHelper::DoInstall(Ptr<EnergySource> source) const
+Ptr<energy::EnergyHarvester>
+BasicEnergyHarvesterHelper::DoInstall(Ptr<energy::EnergySource> source) const
 {
     NS_ASSERT(source);
     Ptr<Node> node = source->GetNode();
 
     // Create a new Basic Energy Harvester
-    Ptr<EnergyHarvester> harvester = m_basicEnergyHarvester.Create<EnergyHarvester>();
+    Ptr<energy::EnergyHarvester> harvester =
+        m_basicEnergyHarvester.Create<energy::EnergyHarvester>();
     NS_ASSERT(harvester);
 
     // Connect the Basic Energy Harvester to the Energy Source
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/basic-energy-harvester-helper.h ns-3.42/src/energy/helper/basic-energy-harvester-helper.h
--- ns-3.41/src/energy/helper/basic-energy-harvester-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/basic-energy-harvester-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -42,7 +42,7 @@
     void Set(std::string name, const AttributeValue& v) override;
 
   private:
-    Ptr<EnergyHarvester> DoInstall(Ptr<EnergySource> source) const override;
+    Ptr<energy::EnergyHarvester> DoInstall(Ptr<energy::EnergySource> source) const override;
 
   private:
     ObjectFactory m_basicEnergyHarvester; //!< Energy source factory
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/basic-energy-source-helper.cc ns-3.42/src/energy/helper/basic-energy-source-helper.cc
--- ns-3.41/src/energy/helper/basic-energy-source-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/basic-energy-source-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -39,11 +39,11 @@
     m_basicEnergySource.Set(name, v);
 }
 
-Ptr<EnergySource>
+Ptr<energy::EnergySource>
 BasicEnergySourceHelper::DoInstall(Ptr<Node> node) const
 {
     NS_ASSERT(node);
-    Ptr<EnergySource> source = m_basicEnergySource.Create<EnergySource>();
+    Ptr<energy::EnergySource> source = m_basicEnergySource.Create<energy::EnergySource>();
     NS_ASSERT(source);
     source->SetNode(node);
     return source;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/basic-energy-source-helper.h ns-3.42/src/energy/helper/basic-energy-source-helper.h
--- ns-3.41/src/energy/helper/basic-energy-source-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/basic-energy-source-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -41,7 +41,7 @@
     void Set(std::string name, const AttributeValue& v) override;
 
   private:
-    Ptr<EnergySource> DoInstall(Ptr<Node> node) const override;
+    Ptr<energy::EnergySource> DoInstall(Ptr<Node> node) const override;
 
   private:
     ObjectFactory m_basicEnergySource; //!< Energy source factory
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-harvester-container.cc ns-3.42/src/energy/helper/energy-harvester-container.cc
--- ns-3.41/src/energy/helper/energy-harvester-container.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-harvester-container.cc	2024-05-29 15:29:46.948073100 -0700
@@ -25,9 +25,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("EnergyHarvesterContainer");
-
 NS_OBJECT_ENSURE_REGISTERED(EnergyHarvesterContainer);
 
 TypeId
@@ -160,4 +161,5 @@
     }
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-harvester-container.h ns-3.42/src/energy/helper/energy-harvester-container.h
--- ns-3.41/src/energy/helper/energy-harvester-container.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-harvester-container.h	2024-05-29 15:29:46.948073100 -0700
@@ -29,6 +29,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 class EnergyHarvester;
 
@@ -188,6 +190,7 @@
     std::vector<Ptr<EnergyHarvester>> m_harvesters; //!< Harvester container
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* defined(ENERGY_HARVESTER_CONTAINER_H) */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-harvester-helper.cc ns-3.42/src/energy/helper/energy-harvester-helper.cc
--- ns-3.41/src/energy/helper/energy-harvester-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-harvester-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -33,32 +33,32 @@
 {
 }
 
-EnergyHarvesterContainer
-EnergyHarvesterHelper::Install(Ptr<EnergySource> source) const
+energy::EnergyHarvesterContainer
+EnergyHarvesterHelper::Install(Ptr<energy::EnergySource> source) const
 {
-    return Install(EnergySourceContainer(source));
+    return Install(energy::EnergySourceContainer(source));
 }
 
-EnergyHarvesterContainer
-EnergyHarvesterHelper::Install(EnergySourceContainer sourceContainer) const
+energy::EnergyHarvesterContainer
+EnergyHarvesterHelper::Install(energy::EnergySourceContainer sourceContainer) const
 {
-    EnergyHarvesterContainer container;
+    energy::EnergyHarvesterContainer container;
     for (auto i = sourceContainer.Begin(); i != sourceContainer.End(); ++i)
     {
-        Ptr<EnergyHarvester> harvester = DoInstall(*i);
+        Ptr<energy::EnergyHarvester> harvester = DoInstall(*i);
         container.Add(harvester);
         Ptr<Node> node = (*i)->GetNode();
         /*
          * Check if EnergyHarvesterContainer is already aggregated to target node. If
          * not, create a new EnergyHarvesterContainer and aggregate it to the node.
          */
-        Ptr<EnergyHarvesterContainer> EnergyHarvesterContainerOnNode =
-            node->GetObject<EnergyHarvesterContainer>();
+        Ptr<energy::EnergyHarvesterContainer> EnergyHarvesterContainerOnNode =
+            node->GetObject<energy::EnergyHarvesterContainer>();
         if (!EnergyHarvesterContainerOnNode)
         {
             ObjectFactory fac;
             fac.SetTypeId("ns3::EnergyHarvesterContainer");
-            EnergyHarvesterContainerOnNode = fac.Create<EnergyHarvesterContainer>();
+            EnergyHarvesterContainerOnNode = fac.Create<energy::EnergyHarvesterContainer>();
             EnergyHarvesterContainerOnNode->Add(harvester);
             node->AggregateObject(EnergyHarvesterContainerOnNode);
         }
@@ -70,10 +70,10 @@
     return container;
 }
 
-EnergyHarvesterContainer
+energy::EnergyHarvesterContainer
 EnergyHarvesterHelper::Install(std::string sourceName) const
 {
-    Ptr<EnergySource> source = Names::Find<EnergySource>(sourceName);
+    Ptr<energy::EnergySource> source = Names::Find<energy::EnergySource>(sourceName);
     return Install(source);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-harvester-helper.h ns-3.42/src/energy/helper/energy-harvester-helper.h
--- ns-3.41/src/energy/helper/energy-harvester-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-harvester-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -60,7 +60,7 @@
      *
      * This function installs an EnergyHarvester onto an energy source.
      */
-    EnergyHarvesterContainer Install(Ptr<EnergySource> source) const;
+    energy::EnergyHarvesterContainer Install(Ptr<energy::EnergySource> source) const;
 
     /**
      * \param sourceContainer List of nodes where EnergyHarvester will be installed.
@@ -68,7 +68,7 @@
      *
      * This function installs an EnergyHarvester onto a list of energy sources.
      */
-    EnergyHarvesterContainer Install(EnergySourceContainer sourceContainer) const;
+    energy::EnergyHarvesterContainer Install(energy::EnergySourceContainer sourceContainer) const;
 
     /**
      * \param sourceName Name of node where EnergyHarvester will be installed.
@@ -76,7 +76,7 @@
      *
      * This function installs an EnergyHarvester onto a node.
      */
-    EnergyHarvesterContainer Install(std::string sourceName) const;
+    energy::EnergyHarvesterContainer Install(std::string sourceName) const;
 
   private:
     /**
@@ -88,7 +88,7 @@
      * the installation process (eg. installing EnergyHarvester on set of nodes) is
      * implemented in the EnergyHarvesterHelper base class.
      */
-    virtual Ptr<EnergyHarvester> DoInstall(Ptr<EnergySource> source) const = 0;
+    virtual Ptr<energy::EnergyHarvester> DoInstall(Ptr<energy::EnergySource> source) const = 0;
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-model-helper.cc ns-3.42/src/energy/helper/energy-model-helper.cc
--- ns-3.41/src/energy/helper/energy-model-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-model-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -32,31 +32,31 @@
 {
 }
 
-EnergySourceContainer
+energy::EnergySourceContainer
 EnergySourceHelper::Install(Ptr<Node> node) const
 {
     return Install(NodeContainer(node));
 }
 
-EnergySourceContainer
+energy::EnergySourceContainer
 EnergySourceHelper::Install(NodeContainer c) const
 {
-    EnergySourceContainer container;
+    energy::EnergySourceContainer container;
     for (auto i = c.Begin(); i != c.End(); ++i)
     {
-        Ptr<EnergySource> src = DoInstall(*i);
+        Ptr<energy::EnergySource> src = DoInstall(*i);
         container.Add(src);
         /*
          * Check if EnergySourceContainer is already aggregated to target node. If
          * not, create a new EnergySourceContainer and aggregate it to node.
          */
-        Ptr<EnergySourceContainer> EnergySourceContainerOnNode =
-            (*i)->GetObject<EnergySourceContainer>();
+        Ptr<energy::EnergySourceContainer> EnergySourceContainerOnNode =
+            (*i)->GetObject<energy::EnergySourceContainer>();
         if (!EnergySourceContainerOnNode)
         {
             ObjectFactory fac;
             fac.SetTypeId("ns3::EnergySourceContainer");
-            EnergySourceContainerOnNode = fac.Create<EnergySourceContainer>();
+            EnergySourceContainerOnNode = fac.Create<energy::EnergySourceContainer>();
             EnergySourceContainerOnNode->Add(src);
             (*i)->AggregateObject(EnergySourceContainerOnNode);
         }
@@ -68,14 +68,14 @@
     return container;
 }
 
-EnergySourceContainer
+energy::EnergySourceContainer
 EnergySourceHelper::Install(std::string nodeName) const
 {
     Ptr<Node> node = Names::Find<Node>(nodeName);
     return Install(node);
 }
 
-EnergySourceContainer
+energy::EnergySourceContainer
 EnergySourceHelper::InstallAll() const
 {
     return Install(NodeContainer::GetGlobal());
@@ -88,30 +88,30 @@
 {
 }
 
-DeviceEnergyModelContainer
-DeviceEnergyModelHelper::Install(Ptr<NetDevice> device, Ptr<EnergySource> source) const
+energy::DeviceEnergyModelContainer
+DeviceEnergyModelHelper::Install(Ptr<NetDevice> device, Ptr<energy::EnergySource> source) const
 {
     NS_ASSERT(device);
     NS_ASSERT(source);
     // check to make sure source and net device are on the same node
     NS_ASSERT(device->GetNode() == source->GetNode());
-    DeviceEnergyModelContainer container(DoInstall(device, source));
+    energy::DeviceEnergyModelContainer container(DoInstall(device, source));
     return container;
 }
 
-DeviceEnergyModelContainer
+energy::DeviceEnergyModelContainer
 DeviceEnergyModelHelper::Install(NetDeviceContainer deviceContainer,
-                                 EnergySourceContainer sourceContainer) const
+                                 energy::EnergySourceContainer sourceContainer) const
 {
     NS_ASSERT(deviceContainer.GetN() <= sourceContainer.GetN());
-    DeviceEnergyModelContainer container;
+    energy::DeviceEnergyModelContainer container;
     auto dev = deviceContainer.Begin();
     auto src = sourceContainer.Begin();
     while (dev != deviceContainer.End())
     {
         // check to make sure source and net device are on the same node
         NS_ASSERT((*dev)->GetNode() == (*src)->GetNode());
-        Ptr<DeviceEnergyModel> model = DoInstall(*dev, *src);
+        Ptr<energy::DeviceEnergyModel> model = DoInstall(*dev, *src);
         container.Add(model);
         dev++;
         src++;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-model-helper.h ns-3.42/src/energy/helper/energy-model-helper.h
--- ns-3.41/src/energy/helper/energy-model-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-model-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -62,7 +62,7 @@
      *
      * This function installs an EnergySource onto a node.
      */
-    EnergySourceContainer Install(Ptr<Node> node) const;
+    energy::EnergySourceContainer Install(Ptr<Node> node) const;
 
     /**
      * \param c List of nodes where EnergySource will be installed.
@@ -70,7 +70,7 @@
      *
      * This function installs an EnergySource onto a list of nodes.
      */
-    EnergySourceContainer Install(NodeContainer c) const;
+    energy::EnergySourceContainer Install(NodeContainer c) const;
 
     /**
      * \param nodeName Name of node where EnergySource will be installed.
@@ -78,14 +78,14 @@
      *
      * This function installs an EnergySource onto a node.
      */
-    EnergySourceContainer Install(std::string nodeName) const;
+    energy::EnergySourceContainer Install(std::string nodeName) const;
 
     /**
      * \brief This function installs an EnergySource on all nodes in simulation.
      *
      * \returns An EnergySourceContainer which contains all the EnergySources.
      */
-    EnergySourceContainer InstallAll() const;
+    energy::EnergySourceContainer InstallAll() const;
 
   private:
     /**
@@ -97,7 +97,7 @@
      * the installation process (eg. installing EnergySource on set of nodes) is
      * implemented in the EnergySourceHelper base class.
      */
-    virtual Ptr<EnergySource> DoInstall(Ptr<Node> node) const = 0;
+    virtual Ptr<energy::EnergySource> DoInstall(Ptr<Node> node) const = 0;
 };
 
 /**
@@ -132,7 +132,8 @@
      * Installs an DeviceEnergyModel with a specified EnergySource onto a
      * xNetDevice.
      */
-    DeviceEnergyModelContainer Install(Ptr<NetDevice> device, Ptr<EnergySource> source) const;
+    energy::DeviceEnergyModelContainer Install(Ptr<NetDevice> device,
+                                               Ptr<energy::EnergySource> source) const;
 
     /**
      * \param deviceContainer List of NetDevices to be install DeviceEnergyModel
@@ -144,8 +145,8 @@
      * Installs DeviceEnergyModels with specified EnergySources onto a list of
      * NetDevices.
      */
-    DeviceEnergyModelContainer Install(NetDeviceContainer deviceContainer,
-                                       EnergySourceContainer sourceContainer) const;
+    energy::DeviceEnergyModelContainer Install(NetDeviceContainer deviceContainer,
+                                               energy::EnergySourceContainer sourceContainer) const;
 
   private:
     /**
@@ -158,8 +159,8 @@
      * node. The rest of the installation process (eg. installing EnergySource on
      * set of nodes) is implemented in the DeviceEnergyModelHelper base class.
      */
-    virtual Ptr<DeviceEnergyModel> DoInstall(Ptr<NetDevice> device,
-                                             Ptr<EnergySource> source) const = 0;
+    virtual Ptr<energy::DeviceEnergyModel> DoInstall(Ptr<NetDevice> device,
+                                                     Ptr<energy::EnergySource> source) const = 0;
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-source-container.cc ns-3.42/src/energy/helper/energy-source-container.cc
--- ns-3.41/src/energy/helper/energy-source-container.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-source-container.cc	2024-05-29 15:29:46.948073100 -0700
@@ -25,6 +25,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_OBJECT_ENSURE_REGISTERED(EnergySourceContainer);
 
@@ -141,4 +143,5 @@
     }
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/energy-source-container.h ns-3.42/src/energy/helper/energy-source-container.h
--- ns-3.41/src/energy/helper/energy-source-container.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/energy-source-container.h	2024-05-29 15:29:46.948073100 -0700
@@ -30,6 +30,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -181,6 +183,7 @@
     std::vector<Ptr<EnergySource>> m_sources; //!< Energy source container
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* ENERGY_SOURCE_CONTAINER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/generic-battery-model-helper.cc ns-3.42/src/energy/helper/generic-battery-model-helper.cc
--- ns-3.41/src/energy/helper/generic-battery-model-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/generic-battery-model-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -37,20 +37,21 @@
     m_batteryModel.Set(name, v);
 }
 
-Ptr<EnergySource>
+Ptr<energy::EnergySource>
 GenericBatteryModelHelper::DoInstall(Ptr<Node> node) const
 {
     NS_ASSERT(node != nullptr);
-    Ptr<EnergySource> energySource = m_batteryModel.Create<EnergySource>();
+    Ptr<energy::EnergySource> energySource = m_batteryModel.Create<energy::EnergySource>();
     NS_ASSERT(energySource != nullptr);
     energySource->SetNode(node);
     return energySource;
 }
 
-Ptr<EnergySourceContainer>
+Ptr<energy::EnergySourceContainer>
 GenericBatteryModelHelper::Install(NodeContainer c) const
 {
-    Ptr<EnergySourceContainer> batteryContainer = CreateObject<EnergySourceContainer>();
+    Ptr<energy::EnergySourceContainer> batteryContainer =
+        CreateObject<energy::EnergySourceContainer>();
     for (auto i = c.Begin(); i != c.End(); i++)
     {
         batteryContainer->Add(DoInstall(*i));
@@ -58,48 +59,50 @@
     return batteryContainer;
 }
 
-Ptr<EnergySource>
-GenericBatteryModelHelper::Install(Ptr<Node> node, BatteryModel bm) const
+Ptr<energy::EnergySource>
+GenericBatteryModelHelper::Install(Ptr<Node> node, energy::BatteryModel bm) const
 {
     NS_ASSERT(node != nullptr);
-    Ptr<EnergySource> energySource = m_batteryModel.Create<EnergySource>();
+    Ptr<energy::EnergySource> energySource = m_batteryModel.Create<energy::EnergySource>();
     NS_ASSERT(energySource != nullptr);
 
-    energySource->SetAttribute("FullVoltage", DoubleValue(g_batteryPreset[bm].vFull));
-    energySource->SetAttribute("MaxCapacity", DoubleValue(g_batteryPreset[bm].qMax));
+    energySource->SetAttribute("FullVoltage", DoubleValue(energy::g_batteryPreset[bm].vFull));
+    energySource->SetAttribute("MaxCapacity", DoubleValue(energy::g_batteryPreset[bm].qMax));
 
-    energySource->SetAttribute("NominalVoltage", DoubleValue(g_batteryPreset[bm].vNom));
-    energySource->SetAttribute("NominalCapacity", DoubleValue(g_batteryPreset[bm].qNom));
+    energySource->SetAttribute("NominalVoltage", DoubleValue(energy::g_batteryPreset[bm].vNom));
+    energySource->SetAttribute("NominalCapacity", DoubleValue(energy::g_batteryPreset[bm].qNom));
 
-    energySource->SetAttribute("ExponentialVoltage", DoubleValue(g_batteryPreset[bm].vExp));
-    energySource->SetAttribute("ExponentialCapacity", DoubleValue(g_batteryPreset[bm].qExp));
+    energySource->SetAttribute("ExponentialVoltage", DoubleValue(energy::g_batteryPreset[bm].vExp));
+    energySource->SetAttribute("ExponentialCapacity",
+                               DoubleValue(energy::g_batteryPreset[bm].qExp));
 
     energySource->SetAttribute("InternalResistance",
-                               DoubleValue(g_batteryPreset[bm].internalResistance));
+                               DoubleValue(energy::g_batteryPreset[bm].internalResistance));
     energySource->SetAttribute("TypicalDischargeCurrent",
-                               DoubleValue(g_batteryPreset[bm].typicalCurrent));
-    energySource->SetAttribute("CutoffVoltage", DoubleValue(g_batteryPreset[bm].cuttoffVoltage));
+                               DoubleValue(energy::g_batteryPreset[bm].typicalCurrent));
+    energySource->SetAttribute("CutoffVoltage",
+                               DoubleValue(energy::g_batteryPreset[bm].cuttoffVoltage));
 
-    energySource->SetAttribute("BatteryType", EnumValue(g_batteryPreset[bm].batteryType));
+    energySource->SetAttribute("BatteryType", EnumValue(energy::g_batteryPreset[bm].batteryType));
 
     energySource->SetNode(node);
     return energySource;
 }
 
-EnergySourceContainer
-GenericBatteryModelHelper::Install(NodeContainer c, BatteryModel bm) const
+energy::EnergySourceContainer
+GenericBatteryModelHelper::Install(NodeContainer c, energy::BatteryModel bm) const
 {
-    EnergySourceContainer batteryContainer;
+    energy::EnergySourceContainer batteryContainer;
     for (auto i = c.Begin(); i != c.End(); i++)
     {
-        Ptr<EnergySource> energySource = Install(*i, bm);
+        Ptr<energy::EnergySource> energySource = Install(*i, bm);
         batteryContainer.Add(energySource);
     }
     return batteryContainer;
 }
 
 void
-GenericBatteryModelHelper::SetCellPack(Ptr<EnergySource> energySource,
+GenericBatteryModelHelper::SetCellPack(Ptr<energy::EnergySource> energySource,
                                        uint8_t series,
                                        uint8_t parallel) const
 {
@@ -141,7 +144,7 @@
 }
 
 void
-GenericBatteryModelHelper::SetCellPack(EnergySourceContainer energySourceContainer,
+GenericBatteryModelHelper::SetCellPack(energy::EnergySourceContainer energySourceContainer,
                                        uint8_t series,
                                        uint8_t parallel) const
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/generic-battery-model-helper.h ns-3.42/src/energy/helper/generic-battery-model-helper.h
--- ns-3.41/src/energy/helper/generic-battery-model-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/generic-battery-model-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -55,7 +55,7 @@
      * \param c The node container
      * \returns An EnergySourceContainer which contains all the EnergySources.
      */
-    Ptr<EnergySourceContainer> Install(NodeContainer c) const;
+    Ptr<energy::EnergySourceContainer> Install(NodeContainer c) const;
 
     /**
      * This function installs an energy source (battery) into a node.
@@ -64,7 +64,7 @@
      * \param bm The battery model that will be install to the node.
      * \returns A pointer to the energy source object used.
      */
-    Ptr<EnergySource> Install(Ptr<Node> node, BatteryModel bm) const;
+    Ptr<energy::EnergySource> Install(Ptr<Node> node, energy::BatteryModel bm) const;
 
     /**
      * This function installs energy sources in a group of nodes in a
@@ -74,7 +74,7 @@
      * \param bm The battery model that will be install to the nodes in the node container.
      * \returns An EnergySourceContainer which contains all the EnergySources.
      */
-    EnergySourceContainer Install(NodeContainer c, BatteryModel bm) const;
+    energy::EnergySourceContainer Install(NodeContainer c, energy::BatteryModel bm) const;
 
     /**
      * This function takes an existing energy source and transform its values to form
@@ -86,7 +86,9 @@
      * \param series The number of cells connected in series.
      * \param parallel The number of cells connected in parallel.
      */
-    void SetCellPack(Ptr<EnergySource> energySource, uint8_t series, uint8_t parallel) const;
+    void SetCellPack(Ptr<energy::EnergySource> energySource,
+                     uint8_t series,
+                     uint8_t parallel) const;
 
     /**
      * This function takes an existing energy source container and transform the values
@@ -99,7 +101,7 @@
      * \param series The number of cells connected in series.
      * \param parallel The number of cells connected in parallel.
      */
-    void SetCellPack(EnergySourceContainer energySourceContainer,
+    void SetCellPack(energy::EnergySourceContainer energySourceContainer,
                      uint8_t series,
                      uint8_t parallel) const;
 
@@ -113,7 +115,7 @@
      * \param node Pointer to node where the energy source is to be installed.
      * \returns Pointer to the created EnergySource.
      */
-    Ptr<EnergySource> DoInstall(Ptr<Node> node) const override;
+    Ptr<energy::EnergySource> DoInstall(Ptr<Node> node) const override;
 
   private:
     ObjectFactory m_batteryModel; //!< The energy source (battery) used by this helper.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/li-ion-energy-source-helper.cc ns-3.42/src/energy/helper/li-ion-energy-source-helper.cc
--- ns-3.41/src/energy/helper/li-ion-energy-source-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/li-ion-energy-source-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -41,11 +41,11 @@
     m_liIonEnergySource.Set(name, v);
 }
 
-Ptr<EnergySource>
+Ptr<energy::EnergySource>
 LiIonEnergySourceHelper::DoInstall(Ptr<Node> node) const
 {
     NS_ASSERT(node);
-    Ptr<EnergySource> source = m_liIonEnergySource.Create<EnergySource>();
+    Ptr<energy::EnergySource> source = m_liIonEnergySource.Create<energy::EnergySource>();
     NS_ASSERT(source);
     source->SetNode(node);
     return source;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/li-ion-energy-source-helper.h ns-3.42/src/energy/helper/li-ion-energy-source-helper.h
--- ns-3.41/src/energy/helper/li-ion-energy-source-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/li-ion-energy-source-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -43,7 +43,7 @@
     void Set(std::string name, const AttributeValue& v) override;
 
   private:
-    Ptr<EnergySource> DoInstall(Ptr<Node> node) const override;
+    Ptr<energy::EnergySource> DoInstall(Ptr<Node> node) const override;
 
   private:
     ObjectFactory m_liIonEnergySource; //!< LiIon Battery factory
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/rv-battery-model-helper.cc ns-3.42/src/energy/helper/rv-battery-model-helper.cc
--- ns-3.41/src/energy/helper/rv-battery-model-helper.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/rv-battery-model-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -39,11 +39,11 @@
     m_rvBatteryModel.Set(name, v);
 }
 
-Ptr<EnergySource>
+Ptr<energy::EnergySource>
 RvBatteryModelHelper::DoInstall(Ptr<Node> node) const
 {
     NS_ASSERT(node);
-    Ptr<EnergySource> source = m_rvBatteryModel.Create<EnergySource>();
+    Ptr<energy::EnergySource> source = m_rvBatteryModel.Create<energy::EnergySource>();
     NS_ASSERT(source);
     source->SetNode(node);
     return source;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/helper/rv-battery-model-helper.h ns-3.42/src/energy/helper/rv-battery-model-helper.h
--- ns-3.41/src/energy/helper/rv-battery-model-helper.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/helper/rv-battery-model-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -41,7 +41,7 @@
     void Set(std::string name, const AttributeValue& v) override;
 
   private:
-    Ptr<EnergySource> DoInstall(Ptr<Node> node) const override;
+    Ptr<energy::EnergySource> DoInstall(Ptr<Node> node) const override;
 
   private:
     ObjectFactory m_rvBatteryModel; //!< RV Battery factory
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/basic-energy-harvester.cc ns-3.42/src/energy/model/basic-energy-harvester.cc
--- ns-3.41/src/energy/model/basic-energy-harvester.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/basic-energy-harvester.cc	2024-05-29 15:29:46.948073100 -0700
@@ -29,9 +29,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("BasicEnergyHarvester");
-
 NS_OBJECT_ENSURE_REGISTERED(BasicEnergyHarvester);
 
 TypeId
@@ -183,4 +184,5 @@
     return m_harvestedPower;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/basic-energy-harvester.h ns-3.42/src/energy/model/basic-energy-harvester.h
--- ns-3.41/src/energy/model/basic-energy-harvester.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/basic-energy-harvester.h	2024-05-29 15:29:46.948073100 -0700
@@ -33,6 +33,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -128,6 +130,7 @@
     Time m_harvestedPowerUpdateInterval;   //!< harvestable energy update interval
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* defined(BASIC_ENERGY_HARVESTER) */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/basic-energy-source.cc ns-3.42/src/energy/model/basic-energy-source.cc
--- ns-3.41/src/energy/model/basic-energy-source.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/basic-energy-source.cc	2024-05-29 15:29:46.948073100 -0700
@@ -27,9 +27,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("BasicEnergySource");
-
 NS_OBJECT_ENSURE_REGISTERED(BasicEnergySource);
 
 TypeId
@@ -231,4 +232,5 @@
     NS_LOG_DEBUG("BasicEnergySource:Remaining energy = " << m_remainingEnergyJ);
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/basic-energy-source.h ns-3.42/src/energy/model/basic-energy-source.h
--- ns-3.41/src/energy/model/basic-energy-source.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/basic-energy-source.h	2024-05-29 15:29:46.948073100 -0700
@@ -28,6 +28,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -155,6 +157,7 @@
     Time m_energyUpdateInterval;            //!< energy update interval
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* BASIC_ENERGY_SOURCE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/device-energy-model.cc ns-3.42/src/energy/model/device-energy-model.cc
--- ns-3.41/src/energy/model/device-energy-model.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/device-energy-model.cc	2024-05-29 15:29:46.948073100 -0700
@@ -23,9 +23,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("DeviceEnergyModel");
-
 NS_OBJECT_ENSURE_REGISTERED(DeviceEnergyModel);
 
 TypeId
@@ -63,4 +64,5 @@
     return 0.0;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/device-energy-model-container.cc ns-3.42/src/energy/model/device-energy-model-container.cc
--- ns-3.41/src/energy/model/device-energy-model-container.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/device-energy-model-container.cc	2024-05-29 15:29:46.948073100 -0700
@@ -26,6 +26,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("DeviceEnergyModelContainer");
 
@@ -119,4 +121,5 @@
     m_models.clear();
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/device-energy-model-container.h ns-3.42/src/energy/model/device-energy-model-container.h
--- ns-3.41/src/energy/model/device-energy-model-container.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/device-energy-model-container.h	2024-05-29 15:29:46.948073100 -0700
@@ -29,6 +29,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -173,6 +175,7 @@
     std::vector<Ptr<DeviceEnergyModel>> m_models; //!< Container of Energy models
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* DEVICE_ENERGY_MODEL_CONTAINER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/device-energy-model.h ns-3.42/src/energy/model/device-energy-model.h
--- ns-3.41/src/energy/model/device-energy-model.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/device-energy-model.h	2024-05-29 15:29:46.948073100 -0700
@@ -27,6 +27,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 class EnergySource;
 
@@ -121,6 +123,7 @@
     virtual double DoGetCurrentA() const;
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* DEVICE_ENERGY_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/energy-harvester.cc ns-3.42/src/energy/model/energy-harvester.cc
--- ns-3.41/src/energy/model/energy-harvester.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/energy-harvester.cc	2024-05-29 15:29:46.948073100 -0700
@@ -24,9 +24,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("EnergyHarvester");
-
 NS_OBJECT_ENSURE_REGISTERED(EnergyHarvester);
 
 TypeId
@@ -100,4 +101,5 @@
     return 0.0;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/energy-harvester.h ns-3.42/src/energy/model/energy-harvester.h
--- ns-3.41/src/energy/model/energy-harvester.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/energy-harvester.h	2024-05-29 15:29:46.948073100 -0700
@@ -32,6 +32,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 class EnergySource;
 
@@ -130,6 +132,7 @@
   protected:
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* defined(ENERGY_HARVESTER_H) */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/energy-source.cc ns-3.42/src/energy/model/energy-source.cc
--- ns-3.41/src/energy/model/energy-source.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/energy-source.cc	2024-05-29 15:29:46.948073100 -0700
@@ -28,9 +28,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("EnergySource");
-
 NS_OBJECT_ENSURE_REGISTERED(EnergySource);
 
 TypeId
@@ -237,4 +238,5 @@
     m_node = nullptr;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/energy-source.h ns-3.42/src/energy/model/energy-source.h
--- ns-3.41/src/energy/model/energy-source.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/energy-source.h	2024-05-29 15:29:46.948073100 -0700
@@ -35,6 +35,10 @@
 
 namespace ns3
 {
+namespace energy
+{
+
+class EnergyHarvester;
 
 /**
  * \defgroup energy Energy Models
@@ -80,9 +84,6 @@
  * energy in different units (eg. kWh), a simple converter function should
  * suffice.
  */
-
-class EnergyHarvester;
-
 class EnergySource : public Object
 {
   public:
@@ -253,6 +254,7 @@
     void BreakDeviceEnergyModelRefCycle();
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* ENERGY_SOURCE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/generic-battery-model.cc ns-3.42/src/energy/model/generic-battery-model.cc
--- ns-3.41/src/energy/model/generic-battery-model.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/generic-battery-model.cc	2024-05-29 15:29:46.948073100 -0700
@@ -32,9 +32,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("GenericBatteryModel");
-
 NS_OBJECT_ENSURE_REGISTERED(GenericBatteryModel);
 
 TypeId
@@ -86,7 +87,7 @@
                           MakeDoubleAccessor(&GenericBatteryModel::m_internalResistance),
                           MakeDoubleChecker<double>())
             .AddAttribute("TypicalDischargeCurrent",
-                          "Typical discharge current used in manufacters datasheets (A)",
+                          "Typical discharge current used in manufacturers datasheets (A)",
                           DoubleValue(2.33),
                           MakeDoubleAccessor(&GenericBatteryModel::m_typicalCurrent),
                           MakeDoubleChecker<double>())
@@ -435,4 +436,5 @@
     return V;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/generic-battery-model.h ns-3.42/src/energy/model/generic-battery-model.h
--- ns-3.41/src/energy/model/generic-battery-model.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/generic-battery-model.h	2024-05-29 15:29:46.948073100 -0700
@@ -31,6 +31,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -309,6 +311,7 @@
     GenericBatteryType m_batteryType; //!< Indicates the battery type used by the model
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* GENERIC_BATTERY_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/li-ion-energy-source.cc ns-3.42/src/energy/model/li-ion-energy-source.cc
--- ns-3.41/src/energy/model/li-ion-energy-source.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/li-ion-energy-source.cc	2024-05-29 15:29:46.948073100 -0700
@@ -29,9 +29,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("LiIonEnergySource");
-
 NS_OBJECT_ENSURE_REGISTERED(LiIonEnergySource);
 
 TypeId
@@ -317,4 +318,5 @@
     return V;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/li-ion-energy-source.h ns-3.42/src/energy/model/li-ion-energy-source.h
--- ns-3.41/src/energy/model/li-ion-energy-source.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/li-ion-energy-source.h	2024-05-29 15:29:46.948073100 -0700
@@ -29,6 +29,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -215,6 +217,7 @@
     double m_minVoltTh;          //!< minimum threshold voltage to consider the battery depleted
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* LI_ION_ENERGY_SOURCE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/rv-battery-model.cc ns-3.42/src/energy/model/rv-battery-model.cc
--- ns-3.41/src/energy/model/rv-battery-model.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/rv-battery-model.cc	2024-05-29 15:29:46.948073100 -0700
@@ -29,9 +29,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("RvBatteryModel");
-
 NS_OBJECT_ENSURE_REGISTERED(RvBatteryModel);
 
 TypeId
@@ -379,4 +380,5 @@
     return delta + 2 * sum;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/rv-battery-model.h ns-3.42/src/energy/model/rv-battery-model.h
--- ns-3.41/src/energy/model/rv-battery-model.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/rv-battery-model.h	2024-05-29 15:29:46.948073100 -0700
@@ -28,6 +28,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -263,6 +265,7 @@
     TracedValue<Time> m_lifetime; //!< time of death of the battery
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* RV_BATTERY_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/simple-device-energy-model.cc ns-3.42/src/energy/model/simple-device-energy-model.cc
--- ns-3.41/src/energy/model/simple-device-energy-model.cc	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/simple-device-energy-model.cc	2024-05-29 15:29:46.948073100 -0700
@@ -27,9 +27,10 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 NS_LOG_COMPONENT_DEFINE("SimpleDeviceEnergyModel");
-
 NS_OBJECT_ENSURE_REGISTERED(SimpleDeviceEnergyModel);
 
 TypeId
@@ -132,4 +133,5 @@
     return m_actualCurrentA;
 }
 
+} // namespace energy
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/model/simple-device-energy-model.h ns-3.42/src/energy/model/simple-device-energy-model.h
--- ns-3.41/src/energy/model/simple-device-energy-model.h	2024-02-09 14:44:07.905790000 -0800
+++ ns-3.42/src/energy/model/simple-device-energy-model.h	2024-05-29 15:29:46.948073100 -0700
@@ -27,6 +27,8 @@
 
 namespace ns3
 {
+namespace energy
+{
 
 /**
  * \ingroup energy
@@ -141,6 +143,7 @@
     TracedValue<double> m_totalEnergyConsumption; //!< Total energy consumption trace
 };
 
+} // namespace energy
 } // namespace ns3
 
 #endif /* SIMPLE_DEVICE_ENERGY_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/test/basic-energy-harvester-test.cc ns-3.42/src/energy/test/basic-energy-harvester-test.cc
--- ns-3.41/src/energy/test/basic-energy-harvester-test.cc	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/energy/test/basic-energy-harvester-test.cc	2024-05-29 15:29:46.948073100 -0700
@@ -29,6 +29,7 @@
 #include "ns3/test.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("BasicEnergyHarvesterTestSuite");
 
@@ -133,9 +134,9 @@
 };
 
 BasicEnergyHarvesterTestSuite::BasicEnergyHarvesterTestSuite()
-    : TestSuite("basic-energy-harvester", UNIT)
+    : TestSuite("basic-energy-harvester", Type::UNIT)
 {
-    AddTestCase(new BasicEnergyHarvesterTestCase, TestCase::QUICK);
+    AddTestCase(new BasicEnergyHarvesterTestCase, TestCase::Duration::QUICK);
 }
 
 /// create an instance of the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/test/examples-to-run.py ns-3.42/src/energy/test/examples-to-run.py
--- ns-3.41/src/energy/test/examples-to-run.py	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/energy/test/examples-to-run.py	2024-05-29 15:29:46.948073100 -0700
@@ -18,4 +18,6 @@
 #     (example_name, do_run).
 #
 # See test.py for more information.
-python_examples = []
+python_examples = [
+    ("generic-battery-discharge-example.py", "True"),
+]
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/energy/test/li-ion-energy-source-test.cc ns-3.42/src/energy/test/li-ion-energy-source-test.cc
--- ns-3.41/src/energy/test/li-ion-energy-source-test.cc	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/energy/test/li-ion-energy-source-test.cc	2024-05-29 15:29:46.948073100 -0700
@@ -25,6 +25,7 @@
 #include "ns3/test.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("LiIonEnergySourceTestSuite");
 
@@ -92,9 +93,9 @@
 };
 
 LiIonEnergySourceTestSuite::LiIonEnergySourceTestSuite()
-    : TestSuite("li-ion-energy-source", UNIT)
+    : TestSuite("li-ion-energy-source", Type::UNIT)
 {
-    AddTestCase(new LiIonEnergyTestCase, TestCase::QUICK);
+    AddTestCase(new LiIonEnergyTestCase, TestCase::Duration::QUICK);
 }
 
 /// create an instance of the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/fd-net-device/helper/creator-utils.cc ns-3.42/src/fd-net-device/helper/creator-utils.cc
--- ns-3.41/src/fd-net-device/helper/creator-utils.cc	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/fd-net-device/helper/creator-utils.cc	2024-05-29 15:29:46.948073100 -0700
@@ -113,7 +113,7 @@
     // an "ancillary element" but the msghdr uses the control message termimology
     // so we call it "control."
     //
-    size_t msg_size = sizeof(int);
+    constexpr size_t msg_size = sizeof(int);
     char control[CMSG_SPACE(msg_size)];
 
     //
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/fd-net-device/helper/dpdk-net-device-helper.h ns-3.42/src/fd-net-device/helper/dpdk-net-device-helper.h
--- ns-3.41/src/fd-net-device/helper/dpdk-net-device-helper.h	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/fd-net-device/helper/dpdk-net-device-helper.h	2024-05-29 15:29:46.948073100 -0700
@@ -27,10 +27,9 @@
 {
 
 /**
- * \ingroup dpdk-net-device
+ * \ingroup fd-net-device
  * \brief build a DpdkNetDevice object attached to a physical network
  * interface
- *
  */
 class DpdkNetDeviceHelper : public EmuFdNetDeviceHelper
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/fd-net-device/helper/emu-fd-net-device-helper.cc ns-3.42/src/fd-net-device/helper/emu-fd-net-device-helper.cc
--- ns-3.41/src/fd-net-device/helper/emu-fd-net-device-helper.cc	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/fd-net-device/helper/emu-fd-net-device-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -380,7 +380,7 @@
         // an "ancillary element" but the msghdr uses the control message terminology
         // so we call it "control."
         //
-        size_t msg_size = sizeof(int);
+        constexpr size_t msg_size = sizeof(int);
         char control[CMSG_SPACE(msg_size)];
 
         //
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/fd-net-device/helper/tap-fd-net-device-helper.cc ns-3.42/src/fd-net-device/helper/tap-fd-net-device-helper.cc
--- ns-3.41/src/fd-net-device/helper/tap-fd-net-device-helper.cc	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/fd-net-device/helper/tap-fd-net-device-helper.cc	2024-05-29 15:29:46.948073100 -0700
@@ -349,7 +349,7 @@
         // an "ancillary element" but the msghdr uses the control message termimology
         // so we call it "control."
         //
-        size_t msg_size = sizeof(int);
+        constexpr size_t msg_size = sizeof(int);
         char control[CMSG_SPACE(msg_size)];
 
         //
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/fd-net-device/model/fd-net-device.cc ns-3.42/src/fd-net-device/model/fd-net-device.cc
--- ns-3.41/src/fd-net-device/model/fd-net-device.cc	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/fd-net-device/model/fd-net-device.cc	2024-05-29 15:29:46.948073100 -0700
@@ -752,7 +752,7 @@
 Address
 FdNetDevice::GetBroadcast() const
 {
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/flow-monitor/examples/flowmon-parse-results.py ns-3.42/src/flow-monitor/examples/flowmon-parse-results.py
--- ns-3.41/src/flow-monitor/examples/flowmon-parse-results.py	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/flow-monitor/examples/flowmon-parse-results.py	2024-05-29 15:29:46.952073000 -0700
@@ -1,5 +1,3 @@
-from __future__ import division
-
 import os
 import sys
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/flow-monitor/examples/wifi-olsr-flowmon.py ns-3.42/src/flow-monitor/examples/wifi-olsr-flowmon.py
--- ns-3.41/src/flow-monitor/examples/wifi-olsr-flowmon.py	2024-02-09 14:44:07.909790000 -0800
+++ ns-3.42/src/flow-monitor/examples/wifi-olsr-flowmon.py	2024-05-29 15:29:46.952073000 -0700
@@ -52,35 +52,31 @@
     cmd.AddValue("Plot", "Plot the results using the matplotlib python module", Plot)
     cmd.Parse(argv)
 
-    wifi = ns.CreateObject("WifiHelper")
-    wifiMac = ns.CreateObject("WifiMacHelper")
-    wifiPhy = ns.CreateObject("YansWifiPhyHelper")
-    wifiChannel = ns.wifi.YansWifiChannelHelper.Default()
+    wifi = ns.WifiHelper()
+    wifiMac = ns.WifiMacHelper()
+    wifiPhy = ns.YansWifiPhyHelper()
+    wifiChannel = ns.YansWifiChannelHelper.Default()
     wifiPhy.SetChannel(wifiChannel.Create())
-    ssid = ns.wifi.Ssid("wifi-default")
-    wifiMac.SetType("ns3::AdhocWifiMac", "Ssid", ns.wifi.SsidValue(ssid))
+    ssid = ns.Ssid("wifi-default")
+    wifiMac.SetType("ns3::AdhocWifiMac", "Ssid", ns.SsidValue(ssid))
 
-    internet = ns.internet.InternetStackHelper()
-    list_routing = ns.internet.Ipv4ListRoutingHelper()
-    olsr_routing = ns.olsr.OlsrHelper()
-    static_routing = ns.internet.Ipv4StaticRoutingHelper()
+    internet = ns.InternetStackHelper()
+    list_routing = ns.Ipv4ListRoutingHelper()
+    olsr_routing = ns.OlsrHelper()
+    static_routing = ns.Ipv4StaticRoutingHelper()
     list_routing.Add(static_routing, 0)
     list_routing.Add(olsr_routing, 100)
     internet.SetRoutingHelper(list_routing)
 
-    ipv4Addresses = ns.internet.Ipv4AddressHelper()
-    ipv4Addresses.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
+    ipv4Addresses = ns.Ipv4AddressHelper()
+    ipv4Addresses.SetBase(ns.Ipv4Address("10.0.0.0"), ns.Ipv4Mask("255.255.255.0"))
 
     port = 9  # Discard port(RFC 863)
-    inetAddress = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.0.0.1"), port)
-    onOffHelper = ns.applications.OnOffHelper("ns3::UdpSocketFactory", inetAddress.ConvertTo())
-    onOffHelper.SetAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate("100kbps")))
-    onOffHelper.SetAttribute(
-        "OnTime", ns.core.StringValue("ns3::ConstantRandomVariable[Constant=1]")
-    )
-    onOffHelper.SetAttribute(
-        "OffTime", ns.core.StringValue("ns3::ConstantRandomVariable[Constant=0]")
-    )
+    inetAddress = ns.InetSocketAddress(ns.Ipv4Address("10.0.0.1"), port)
+    onOffHelper = ns.OnOffHelper("ns3::UdpSocketFactory", inetAddress.ConvertTo())
+    onOffHelper.SetAttribute("DataRate", ns.DataRateValue(ns.DataRate("100kbps")))
+    onOffHelper.SetAttribute("OnTime", ns.StringValue("ns3::ConstantRandomVariable[Constant=1]"))
+    onOffHelper.SetAttribute("OffTime", ns.StringValue("ns3::ConstantRandomVariable[Constant=0]"))
 
     addresses = []
     nodes = []
@@ -96,11 +92,11 @@
         for yi in range(num_nodes_side):
             node = nodes.Get(accumulator)
             accumulator += 1
-            container = ns.network.NodeContainer(node)
+            container = ns.NodeContainer(node)
             internet.Install(container)
 
-            mobility = ns.CreateObject("ConstantPositionMobilityModel")
-            mobility.SetPosition(ns.core.Vector(xi * DISTANCE, yi * DISTANCE, 0))
+            mobility = ns.CreateObject[ns.ConstantPositionMobilityModel]()
+            mobility.SetPosition(ns.Vector(xi * DISTANCE, yi * DISTANCE, 0))
             node.AggregateObject(mobility)
 
             device = wifi.Install(wifiPhy, wifiMac, node)
@@ -112,25 +108,25 @@
         # print (i, destaddr)
         onOffHelper.SetAttribute(
             "Remote",
-            ns.network.AddressValue(ns.network.InetSocketAddress(destaddr, port).ConvertTo()),
+            ns.AddressValue(ns.InetSocketAddress(destaddr, port).ConvertTo()),
         )
-        container = ns.network.NodeContainer(node)
+        container = ns.NodeContainer(node)
         app = onOffHelper.Install(container)
-        urv = ns.CreateObject("UniformRandomVariable")  # ns.cppyy.gbl.get_rng()
+        urv = ns.CreateObject[ns.UniformRandomVariable]()  # ns.cppyy.gbl.get_rng()
         startDelay = ns.Seconds(urv.GetValue(20, 30))
         app.Start(startDelay)
 
     # internet.EnablePcapAll("wifi-olsr")
-    flowmon_helper = ns.flow_monitor.FlowMonitorHelper()
-    # flowmon_helper.SetMonitorAttribute("StartTime", ns.core.TimeValue(ns.core.Seconds(31)))
+    flowmon_helper = ns.FlowMonitorHelper()
+    # flowmon_helper.SetMonitorAttribute("StartTime", ns.TimeValue(ns.Seconds(31)))
     monitor = flowmon_helper.InstallAll()
     monitor = flowmon_helper.GetMonitor()
-    monitor.SetAttribute("DelayBinWidth", ns.core.DoubleValue(0.001))
-    monitor.SetAttribute("JitterBinWidth", ns.core.DoubleValue(0.001))
-    monitor.SetAttribute("PacketSizeBinWidth", ns.core.DoubleValue(20))
+    monitor.SetAttribute("DelayBinWidth", ns.DoubleValue(0.001))
+    monitor.SetAttribute("JitterBinWidth", ns.DoubleValue(0.001))
+    monitor.SetAttribute("PacketSizeBinWidth", ns.DoubleValue(20))
 
-    ns.core.Simulator.Stop(ns.core.Seconds(44.0))
-    ns.core.Simulator.Run()
+    ns.Simulator.Stop(ns.Seconds(44.0))
+    ns.Simulator.Run()
 
     def print_stats(os, st):
         print("  Tx Bytes: ", st.txBytes, file=os)
@@ -213,7 +209,7 @@
         print(res)
 
     if Plot.value:
-        import pylab
+        from matplotlib import pyplot as plt
 
         delays = []
         for flow_id, flow_stats in monitor.GetFlowStats():
@@ -221,10 +217,10 @@
             if tupl.protocol == 17 and tupl.sourcePort == 698:
                 continue
             delays.append(flow_stats.delaySum.GetSeconds() / flow_stats.rxPackets)
-        pylab.hist(delays, 20)
-        pylab.xlabel("Delay (s)")
-        pylab.ylabel("Number of Flows")
-        pylab.show()
+        plt.hist(delays, 20)
+        plt.xlabel("Delay (s)")
+        plt.ylabel("Number of Flows")
+        plt.show()
 
     return 0
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/doc/tcp.rst ns-3.42/src/internet/doc/tcp.rst
--- ns-3.41/src/internet/doc/tcp.rst	2024-02-09 14:44:07.917790200 -0800
+++ ns-3.42/src/internet/doc/tcp.rst	2024-05-29 15:29:46.956073300 -0700
@@ -1986,7 +1986,7 @@
          if (h.GetFlags() & TcpHeader::SYN)
            {
              EventId persistentEvent = GetPersistentEvent(SENDER);
-             NS_TEST_ASSERT_MSG_EQ(persistentEvent.IsRunning(), true,
+             NS_TEST_ASSERT_MSG_EQ(persistentEvent.IsPending(), true,
                                    "Persistent event not started");
            }
        }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/examples/neighbor-cache-example.cc ns-3.42/src/internet/examples/neighbor-cache-example.cc
--- ns-3.41/src/internet/examples/neighbor-cache-example.cc	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/examples/neighbor-cache-example.cc	2024-05-29 15:29:46.956073300 -0700
@@ -55,7 +55,7 @@
  *
  * Expected Outputs:
  * IPv4 (default):
- * Generate ARP caches for all deveices (default) :
+ * Generate ARP caches for all devices (default) :
  * \verbatim
   ARP Cache of node 0 at time 0
   10.1.1.2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
@@ -149,7 +149,7 @@
  (size=512) AND (seq=14 time=+1.00001s) \endverbatim
  *
  * IPv6 (--useIPv6):
- * Generate NDISC caches for all deveices (default) :
+ * Generate NDISC caches for all devices (default) :
  * \verbatim
   NDISC Cache of node 0 at time +0s
   2001:1::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/helper/internet-stack-helper.h ns-3.42/src/internet/helper/internet-stack-helper.h
--- ns-3.41/src/internet/helper/internet-stack-helper.h	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/helper/internet-stack-helper.h	2024-05-29 15:29:46.956073300 -0700
@@ -96,7 +96,7 @@
      * and global routing by default. The static routing protocol
      * (ns3::Ipv4StaticRouting) and the global routing protocol are
      * stored in an ns3::Ipv4ListRouting protocol with priorities 0, and -10
-     * by default. If you wish to use different priorites and different
+     * by default. If you wish to use different priorities and different
      * routing protocols, you need to use an adhoc ns3::Ipv4RoutingHelper,
      * such as ns3::OlsrHelper
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/helper/ipv4-address-helper.cc ns-3.42/src/internet/helper/ipv4-address-helper.cc
--- ns-3.41/src/internet/helper/ipv4-address-helper.cc	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/helper/ipv4-address-helper.cc	2024-05-29 15:29:46.956073300 -0700
@@ -48,7 +48,7 @@
     m_mask = 0;
     m_address = 0xffffffff;
     m_base = 0xffffffff;
-    m_shift = 0xffffffff;
+    m_shift = 0;
     m_max = 0xffffffff;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/helper/neighbor-cache-helper.h ns-3.42/src/internet/helper/neighbor-cache-helper.h
--- ns-3.41/src/internet/helper/neighbor-cache-helper.h	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/helper/neighbor-cache-helper.h	2024-05-29 15:29:46.956073300 -0700
@@ -40,7 +40,7 @@
 {
 
 /**
- * \ingroup NeighborCacheHelper
+ * \ingroup internet
  *
  * @brief A helper class to populate neighbor cache.
  *
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/arp-cache.cc ns-3.42/src/internet/model/arp-cache.cc
--- ns-3.41/src/internet/model/arp-cache.cc	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/model/arp-cache.cc	2024-05-29 15:29:46.956073300 -0700
@@ -102,7 +102,7 @@
     Flush();
     m_device = nullptr;
     m_interface = nullptr;
-    if (!m_waitReplyTimer.IsRunning())
+    if (!m_waitReplyTimer.IsPending())
     {
         m_waitReplyTimer.Cancel();
     }
@@ -184,7 +184,7 @@
 ArpCache::StartWaitReplyTimer()
 {
     NS_LOG_FUNCTION(this);
-    if (!m_waitReplyTimer.IsRunning())
+    if (!m_waitReplyTimer.IsPending())
     {
         NS_LOG_LOGIC("Starting WaitReplyTimer at " << Simulator::Now() << " for "
                                                    << m_waitReplyTimeout);
@@ -250,7 +250,7 @@
         delete (*i).second;
     }
     m_arpCache.erase(m_arpCache.begin(), m_arpCache.end());
-    if (m_waitReplyTimer.IsRunning())
+    if (m_waitReplyTimer.IsPending())
     {
         NS_LOG_LOGIC("Stopping WaitReplyTimer at " << Simulator::Now().GetSeconds()
                                                    << " due to ArpCache flush");
@@ -536,7 +536,6 @@
     case ArpCache::Entry::ALIVE:
         return m_arp->GetAliveTimeout();
     case ArpCache::Entry::PERMANENT:
-        return Time::Max();
     case ArpCache::Entry::STATIC_AUTOGENERATED:
         return Time::Max();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/arp-cache.h ns-3.42/src/internet/model/arp-cache.h
--- ns-3.41/src/internet/model/arp-cache.h	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/model/arp-cache.h	2024-05-29 15:29:46.956073300 -0700
@@ -314,7 +314,7 @@
         Address m_macAddress;         //!< entry's MAC address
         Ipv4Address m_ipv4Address;    //!< entry's IP address
         std::list<Ipv4PayloadHeaderPair> m_pending; //!< list of pending packets for the entry's IP
-        uint32_t m_retries;                         //!< rerty counter
+        uint32_t m_retries;                         //!< retry counter
     };
 
   private:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/arp-l3-protocol.cc ns-3.42/src/internet/model/arp-l3-protocol.cc
--- ns-3.41/src/internet/model/arp-l3-protocol.cc	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/model/arp-l3-protocol.cc	2024-05-29 15:29:46.956073300 -0700
@@ -261,7 +261,7 @@
                 else
                 {
                     // ignore this reply which might well be an attempt
-                    // at poisening my arp cache.
+                    // at poisoning my arp cache.
                     NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply from "
                                          << arp.GetSourceIpv4Address()
                                          << " for non-waiting entry -- drop");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/arp-queue-disc-item.cc ns-3.42/src/internet/model/arp-queue-disc-item.cc
--- ns-3.41/src/internet/model/arp-queue-disc-item.cc	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/model/arp-queue-disc-item.cc	2024-05-29 15:29:46.956073300 -0700
@@ -19,6 +19,8 @@
 
 #include "ns3/log.h"
 
+#include <vector>
+
 namespace ns3
 {
 
@@ -104,11 +106,11 @@
 
     /* serialize the addresses and the perturbation in buf */
     uint8_t tmp = 8 + macSrc.GetLength() + macDst.GetLength();
-    uint8_t buf[tmp + 5];
-    ipv4Src.Serialize(buf);
-    ipv4Dst.Serialize(buf + 4);
-    macSrc.CopyTo(buf + 8);
-    macDst.CopyTo(buf + 8 + macSrc.GetLength());
+    std::vector<uint8_t> buf(tmp + 5);
+    ipv4Src.Serialize(buf.data());
+    ipv4Dst.Serialize(buf.data() + 4);
+    macSrc.CopyTo(buf.data() + 8);
+    macDst.CopyTo(buf.data() + 8 + macSrc.GetLength());
     buf[tmp] = type;
     buf[tmp + 1] = (perturbation >> 24) & 0xff;
     buf[tmp + 2] = (perturbation >> 16) & 0xff;
@@ -118,7 +120,7 @@
     // Linux calculates jhash2 (jenkins hash), we calculate murmur3 because it is
     // already available in ns-3
 
-    uint32_t hash = Hash32((char*)buf, tmp + 5);
+    uint32_t hash = Hash32((char*)buf.data(), tmp + 5);
 
     NS_LOG_DEBUG("Hash value " << hash);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/global-route-manager-impl.cc ns-3.42/src/internet/model/global-route-manager-impl.cc
--- ns-3.41/src/internet/model/global-route-manager-impl.cc	2024-02-09 14:44:07.921790100 -0800
+++ ns-3.42/src/internet/model/global-route-manager-impl.cc	2024-05-29 15:29:46.956073300 -0700
@@ -128,7 +128,7 @@
     NS_LOG_FUNCTION(this);
 
     NS_LOG_LOGIC("Children vertices - " << m_children);
-    NS_LOG_LOGIC("Parent verteices - " << m_parents);
+    NS_LOG_LOGIC("Parent vertices - " << m_parents);
 
     // find this node from all its parents and remove the entry of this node
     // from all its parents
@@ -284,7 +284,7 @@
     // always maintain only one root's exit
     m_ecmpRootExits.clear();
     m_ecmpRootExits.emplace_back(nextHop, id);
-    // update the following in order to be backward compatitable with
+    // update the following in order to be backward compatible with
     // GetNextHop and GetOutgoingInterface methods
     m_nextHop = nextHop;
     m_rootOif = id;
@@ -1023,7 +1023,7 @@
             //
             // In the case of point-to-point links, the link data field (m_linkData) of a
             // Global Router Link Record contains the local IP address.  If we look at the
-            // link record describing the link from the perspecive of <w> (the remote
+            // link record describing the link from the perspective of <w> (the remote
             // node from the viewpoint of <v>) back to the root node, we can discover the
             // IP address of the router to which <v> is adjacent.  This is a distinguished
             // address -- the next hop address to get from <v> to <w> and all networks
@@ -1254,12 +1254,8 @@
     for (uint32_t i = 0; i < rlsa->GetNLinkRecords(); i++)
     {
         GlobalRoutingLinkRecord* l = rlsa->GetLinkRecord(i);
-        if (l->GetLinkType() == GlobalRoutingLinkRecord::TransitNetwork)
-        {
-            transits++;
-            transitLink = l;
-        }
-        else if (l->GetLinkType() == GlobalRoutingLinkRecord::PointToPoint)
+        if (l->GetLinkType() == GlobalRoutingLinkRecord::TransitNetwork ||
+            l->GetLinkType() == GlobalRoutingLinkRecord::PointToPoint)
         {
             transits++;
             transitLink = l;
@@ -1972,7 +1968,7 @@
             //
             // Iterate through the link records on the vertex to which we're going to add
             // routes.  To make sure we're being clear, we're going to add routing table
-            // entries to the tables on the node corresping to the root of the SPF tree.
+            // entries to the tables on the node corresponding to the root of the SPF tree.
             // These entries will have routes to the IP addresses we find from looking at
             // the local side of the point-to-point links found on the node described by
             // the vertex <v>.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/icmpv6-l4-protocol.cc ns-3.42/src/internet/model/icmpv6-l4-protocol.cc
--- ns-3.41/src/internet/model/icmpv6-l4-protocol.cc	2024-02-09 14:44:07.925790300 -0800
+++ ns-3.42/src/internet/model/icmpv6-l4-protocol.cc	2024-05-29 15:29:46.960073200 -0700
@@ -421,7 +421,7 @@
 {
     NS_LOG_FUNCTION(this << packet << src << dst << interface);
 
-    if (m_handleRsTimeoutEvent.IsRunning())
+    if (m_handleRsTimeoutEvent.IsPending())
     {
         m_handleRsTimeoutEvent.Cancel();
         // We need to update this in case we need to restart RS retransmissions.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/icmpv6-l4-protocol.h ns-3.42/src/internet/model/icmpv6-l4-protocol.h
--- ns-3.41/src/internet/model/icmpv6-l4-protocol.h	2024-02-09 14:44:07.925790300 -0800
+++ ns-3.42/src/internet/model/icmpv6-l4-protocol.h	2024-05-29 15:29:46.960073200 -0700
@@ -395,7 +395,7 @@
 
     /**
      * \brief Create a neighbor cache.
-     * \param device thet NetDevice
+     * \param device the NetDevice
      * \param interface the IPv6 interface
      * \return a smart pointer of NdCache or 0 if problem
      */
@@ -642,7 +642,7 @@
     /**
      * \brief Multicast RS retransmissions counter [\RFC{7559}].
      *
-     * Zero indicate a first transmission, greater than zero means retranmsisisons.
+     * Zero indicate a first transmission, greater than zero means retransmissions.
      */
     uint32_t m_rsRetransmissionCount{0};
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv4-global-routing.h ns-3.42/src/internet/model/ipv4-global-routing.h
--- ns-3.41/src/internet/model/ipv4-global-routing.h	2024-02-09 14:44:07.925790300 -0800
+++ ns-3.42/src/internet/model/ipv4-global-routing.h	2024-05-29 15:29:46.960073200 -0700
@@ -239,7 +239,7 @@
     /// Set to true if packets are randomly routed among ECMP; set to false for using only one route
     /// consistently
     bool m_randomEcmpRouting;
-    /// Set to true if this interface should respond to interface events by globallly recomputing
+    /// Set to true if this interface should respond to interface events by globally recomputing
     /// routes
     bool m_respondToInterfaceEvents;
     /// A uniform random number generator for randomly routing packets among ECMP
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv4-l3-protocol.cc ns-3.42/src/internet/model/ipv4-l3-protocol.cc
--- ns-3.41/src/internet/model/ipv4-l3-protocol.cc	2024-02-09 14:44:07.929790300 -0800
+++ ns-3.42/src/internet/model/ipv4-l3-protocol.cc	2024-05-29 15:29:46.960073200 -0700
@@ -210,16 +210,12 @@
 Ptr<IpL4Protocol>
 Ipv4L3Protocol::GetProtocol(int protocolNumber) const
 {
-    NS_LOG_FUNCTION(this << protocolNumber);
-
     return GetProtocol(protocolNumber, -1);
 }
 
 Ptr<IpL4Protocol>
 Ipv4L3Protocol::GetProtocol(int protocolNumber, int32_t interfaceIndex) const
 {
-    NS_LOG_FUNCTION(this << protocolNumber << interfaceIndex);
-
     if (interfaceIndex >= 0)
     {
         // try the interface-specific protocol.
@@ -306,7 +302,6 @@
 Ptr<Ipv4RoutingProtocol>
 Ipv4L3Protocol::GetRoutingProtocol() const
 {
-    NS_LOG_FUNCTION(this);
     return m_routingProtocol;
 }
 
@@ -338,12 +333,12 @@
 
     m_fragments.clear();
     m_timeoutEventList.clear();
-    if (m_timeoutEvent.IsRunning())
+    if (m_timeoutEvent.IsPending())
     {
         m_timeoutEvent.Cancel();
     }
 
-    if (m_cleanDpd.IsRunning())
+    if (m_cleanDpd.IsPending())
     {
         m_cleanDpd.Cancel();
     }
@@ -442,7 +437,6 @@
 Ptr<Ipv4Interface>
 Ipv4L3Protocol::GetInterface(uint32_t index) const
 {
-    NS_LOG_FUNCTION(this << index);
     if (index < m_interfaces.size())
     {
         return m_interfaces[index];
@@ -453,14 +447,12 @@
 uint32_t
 Ipv4L3Protocol::GetNInterfaces() const
 {
-    NS_LOG_FUNCTION(this);
     return m_interfaces.size();
 }
 
 int32_t
 Ipv4L3Protocol::GetInterfaceForAddress(Ipv4Address address) const
 {
-    NS_LOG_FUNCTION(this << address);
     int32_t interface = 0;
     for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++, interface++)
     {
@@ -479,7 +471,6 @@
 int32_t
 Ipv4L3Protocol::GetInterfaceForPrefix(Ipv4Address address, Ipv4Mask mask) const
 {
-    NS_LOG_FUNCTION(this << address << mask);
     int32_t interface = 0;
     for (auto i = m_interfaces.begin(); i != m_interfaces.end(); i++, interface++)
     {
@@ -498,8 +489,6 @@
 int32_t
 Ipv4L3Protocol::GetInterfaceForDevice(Ptr<const NetDevice> device) const
 {
-    NS_LOG_FUNCTION(this << device);
-
     auto iter = m_reverseInterfacesContainer.find(device);
     if (iter != m_reverseInterfacesContainer.end())
     {
@@ -512,7 +501,6 @@
 bool
 Ipv4L3Protocol::IsDestinationAddress(Ipv4Address address, uint32_t iif) const
 {
-    NS_LOG_FUNCTION(this << address << iif);
     // First check the incoming interface for a unicast address match
     for (uint32_t i = 0; i < GetNAddresses(iif); i++)
     {
@@ -681,7 +669,6 @@
 Ptr<Icmpv4L4Protocol>
 Ipv4L3Protocol::GetIcmp() const
 {
-    NS_LOG_FUNCTION(this);
     Ptr<IpL4Protocol> prot = GetProtocol(Icmpv4L4Protocol::GetStaticProtocolNumber());
     if (prot)
     {
@@ -696,8 +683,6 @@
 bool
 Ipv4L3Protocol::IsUnicast(Ipv4Address ad) const
 {
-    NS_LOG_FUNCTION(this << ad);
-
     if (ad.IsBroadcast() || ad.IsMulticast())
     {
         return false;
@@ -726,7 +711,6 @@
 bool
 Ipv4L3Protocol::IsUnicast(Ipv4Address ad, Ipv4Mask interfaceMask) const
 {
-    NS_LOG_FUNCTION(this << ad << interfaceMask);
     return !ad.IsMulticast() && !ad.IsSubnetDirectedBroadcast(interfaceMask);
 }
 
@@ -1180,7 +1164,6 @@
 Ipv4InterfaceAddress
 Ipv4L3Protocol::GetAddress(uint32_t interfaceIndex, uint32_t addressIndex) const
 {
-    NS_LOG_FUNCTION(this << interfaceIndex << addressIndex);
     Ptr<Ipv4Interface> interface = GetInterface(interfaceIndex);
     return interface->GetAddress(addressIndex);
 }
@@ -1188,7 +1171,6 @@
 uint32_t
 Ipv4L3Protocol::GetNAddresses(uint32_t interface) const
 {
-    NS_LOG_FUNCTION(this << interface);
     Ptr<Ipv4Interface> iface = GetInterface(interface);
     return iface->GetNAddresses();
 }
@@ -1333,7 +1315,6 @@
 uint16_t
 Ipv4L3Protocol::GetMetric(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv4Interface> interface = GetInterface(i);
     return interface->GetMetric();
 }
@@ -1341,7 +1322,6 @@
 uint16_t
 Ipv4L3Protocol::GetMtu(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv4Interface> interface = GetInterface(i);
     return interface->GetDevice()->GetMtu();
 }
@@ -1349,7 +1329,6 @@
 bool
 Ipv4L3Protocol::IsUp(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv4Interface> interface = GetInterface(i);
     return interface->IsUp();
 }
@@ -1398,7 +1377,6 @@
 bool
 Ipv4L3Protocol::IsForwarding(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv4Interface> interface = GetInterface(i);
     NS_LOG_LOGIC("Forwarding state: " << interface->IsForwarding());
     return interface->IsForwarding();
@@ -1415,7 +1393,6 @@
 Ptr<NetDevice>
 Ipv4L3Protocol::GetNetDevice(uint32_t i)
 {
-    NS_LOG_FUNCTION(this << i);
     return GetInterface(i)->GetDevice();
 }
 
@@ -1433,7 +1410,6 @@
 bool
 Ipv4L3Protocol::GetIpForward() const
 {
-    NS_LOG_FUNCTION(this);
     return m_ipForward;
 }
 
@@ -1447,7 +1423,6 @@
 bool
 Ipv4L3Protocol::GetWeakEsModel() const
 {
-    NS_LOG_FUNCTION(this);
     return !m_strongEndSystemModel;
 }
 
@@ -1461,7 +1436,6 @@
 bool
 Ipv4L3Protocol::GetStrongEndSystemModel() const
 {
-    NS_LOG_FUNCTION(this);
     return m_strongEndSystemModel;
 }
 
@@ -1487,7 +1461,7 @@
     // BEWARE: here we do assume that the header options are not present.
     // a much more complex handling is necessary in case there are options.
     // If (when) IPv4 option headers will be implemented, the following code shall be changed.
-    // Of course also the reassemby code shall be changed as well.
+    // Of course also the reassembly code shall be changed as well.
 
     NS_LOG_FUNCTION(this << *packet << outIfaceMtu << &listFragments);
 
@@ -1826,7 +1800,7 @@
     }
 
     // set cleanup job for new duplicate entries
-    if (!m_cleanDpd.IsRunning() && m_purge.IsStrictlyPositive())
+    if (!m_cleanDpd.IsPending() && m_purge.IsStrictlyPositive())
     {
         m_cleanDpd = Simulator::Schedule(m_expire, &Ipv4L3Protocol::RemoveDuplicates, this);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv4-l3-protocol.h ns-3.42/src/internet/model/ipv4-l3-protocol.h
--- ns-3.41/src/internet/model/ipv4-l3-protocol.h	2024-02-09 14:44:07.929790300 -0800
+++ ns-3.42/src/internet/model/ipv4-l3-protocol.h	2024-05-29 15:29:46.960073200 -0700
@@ -575,7 +575,7 @@
 
         /**
          * \brief Get the complete part of the packet.
-         * \return the part we have comeplete
+         * \return the part we have complete
          */
         Ptr<Packet> GetPartialPacket() const;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv4-raw-socket-impl.cc ns-3.42/src/internet/model/ipv4-raw-socket-impl.cc
--- ns-3.41/src/internet/model/ipv4-raw-socket-impl.cc	2024-02-09 14:44:07.929790300 -0800
+++ ns-3.42/src/internet/model/ipv4-raw-socket-impl.cc	2024-05-29 15:29:46.960073200 -0700
@@ -202,7 +202,6 @@
     }
     InetSocketAddress ad = InetSocketAddress::ConvertFrom(address);
     m_dst = ad.GetIpv4();
-    SetIpTos(ad.GetTos());
     NotifyConnectionSucceeded();
 
     return 0;
@@ -228,7 +227,6 @@
 {
     NS_LOG_FUNCTION(this << p << flags);
     InetSocketAddress to = InetSocketAddress(m_dst, m_protocol);
-    to.SetTos(GetIpTos());
     return SendTo(p, flags, to);
 }
 
@@ -250,7 +248,7 @@
     Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
     Ipv4Address dst = ad.GetIpv4();
     Ipv4Address src = m_src;
-    uint8_t tos = ad.GetTos();
+    uint8_t tos = GetIpTos();
 
     uint8_t priority = GetPriority();
     if (tos)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv6-extension.cc ns-3.42/src/internet/model/ipv6-extension.cc
--- ns-3.41/src/internet/model/ipv6-extension.cc	2024-02-09 14:44:07.933790200 -0800
+++ ns-3.42/src/internet/model/ipv6-extension.cc	2024-05-29 15:29:46.964073200 -0700
@@ -361,7 +361,7 @@
 
     m_fragments.clear();
     m_timeoutEventList.clear();
-    if (m_timeoutEvent.IsRunning())
+    if (m_timeoutEvent.IsPending())
     {
         m_timeoutEvent.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv6-extension-header.cc ns-3.42/src/internet/model/ipv6-extension-header.cc
--- ns-3.41/src/internet/model/ipv6-extension-header.cc	2024-02-09 14:44:07.933790200 -0800
+++ ns-3.42/src/internet/model/ipv6-extension-header.cc	2024-05-29 15:29:46.964073200 -0700
@@ -150,14 +150,14 @@
 uint32_t
 OptionField::GetSerializedSize() const
 {
-    return m_optionData.GetSize() + CalculatePad((Ipv6OptionHeader::Alignment){8, 0});
+    return m_optionData.GetSize() + CalculatePad(Ipv6OptionHeader::Alignment{8, 0});
 }
 
 void
 OptionField::Serialize(Buffer::Iterator start) const
 {
     start.Write(m_optionData.Begin(), m_optionData.End());
-    uint32_t fill = CalculatePad((Ipv6OptionHeader::Alignment){8, 0});
+    uint32_t fill = CalculatePad(Ipv6OptionHeader::Alignment{8, 0});
     NS_LOG_LOGIC("fill with " << fill << " bytes padding");
     switch (fill)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv6-l3-protocol.cc ns-3.42/src/internet/model/ipv6-l3-protocol.cc
--- ns-3.41/src/internet/model/ipv6-l3-protocol.cc	2024-02-09 14:44:07.933790200 -0800
+++ ns-3.42/src/internet/model/ipv6-l3-protocol.cc	2024-05-29 15:29:46.964073200 -0700
@@ -191,7 +191,6 @@
 Ptr<Ipv6RoutingProtocol>
 Ipv6L3Protocol::GetRoutingProtocol() const
 {
-    NS_LOG_FUNCTION(this);
     return m_routingProtocol;
 }
 
@@ -235,8 +234,6 @@
 Ptr<Ipv6Interface>
 Ipv6L3Protocol::GetInterface(uint32_t index) const
 {
-    NS_LOG_FUNCTION(this << index);
-
     if (index < m_interfaces.size())
     {
         return m_interfaces[index];
@@ -247,14 +244,12 @@
 uint32_t
 Ipv6L3Protocol::GetNInterfaces() const
 {
-    NS_LOG_FUNCTION(this);
     return m_nInterfaces;
 }
 
 int32_t
 Ipv6L3Protocol::GetInterfaceForAddress(Ipv6Address address) const
 {
-    NS_LOG_FUNCTION(this << address);
     int32_t index = 0;
 
     for (auto it = m_interfaces.begin(); it != m_interfaces.end(); it++)
@@ -277,7 +272,6 @@
 int32_t
 Ipv6L3Protocol::GetInterfaceForPrefix(Ipv6Address address, Ipv6Prefix mask) const
 {
-    NS_LOG_FUNCTION(this << address << mask);
     int32_t index = 0;
 
     for (auto it = m_interfaces.begin(); it != m_interfaces.end(); it++)
@@ -299,15 +293,12 @@
 Ptr<NetDevice>
 Ipv6L3Protocol::GetNetDevice(uint32_t i)
 {
-    NS_LOG_FUNCTION(this << i);
     return GetInterface(i)->GetDevice();
 }
 
 int32_t
 Ipv6L3Protocol::GetInterfaceForDevice(Ptr<const NetDevice> device) const
 {
-    NS_LOG_FUNCTION(this << device);
-
     auto iter = m_reverseInterfacesContainer.find(device);
     if (iter != m_reverseInterfacesContainer.end())
     {
@@ -459,7 +450,6 @@
 uint32_t
 Ipv6L3Protocol::GetNAddresses(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv6Interface> interface = GetInterface(i);
     return interface->GetNAddresses();
 }
@@ -467,7 +457,6 @@
 Ipv6InterfaceAddress
 Ipv6L3Protocol::GetAddress(uint32_t i, uint32_t addressIndex) const
 {
-    NS_LOG_FUNCTION(this << i << addressIndex);
     Ptr<Ipv6Interface> interface = GetInterface(i);
     return interface->GetAddress(addressIndex);
 }
@@ -524,7 +513,6 @@
 uint16_t
 Ipv6L3Protocol::GetMetric(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv6Interface> interface = GetInterface(i);
     return interface->GetMetric();
 }
@@ -532,8 +520,6 @@
 uint16_t
 Ipv6L3Protocol::GetMtu(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
-
     // RFC 1981, if PMTU is disabled, return the minimum MTU
     if (!m_mtuDiscover)
     {
@@ -554,7 +540,6 @@
 bool
 Ipv6L3Protocol::IsUp(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv6Interface> interface = GetInterface(i);
     return interface->IsUp();
 }
@@ -645,7 +630,6 @@
 bool
 Ipv6L3Protocol::IsForwarding(uint32_t i) const
 {
-    NS_LOG_FUNCTION(this << i);
     Ptr<Ipv6Interface> interface = GetInterface(i);
 
     NS_LOG_LOGIC("Forwarding state: " << interface->IsForwarding());
@@ -722,7 +706,6 @@
 bool
 Ipv6L3Protocol::GetIpForward() const
 {
-    NS_LOG_FUNCTION(this);
     return m_ipForward;
 }
 
@@ -736,7 +719,6 @@
 bool
 Ipv6L3Protocol::GetMtuDiscover() const
 {
-    NS_LOG_FUNCTION(this);
     return m_mtuDiscover;
 }
 
@@ -750,7 +732,6 @@
 bool
 Ipv6L3Protocol::GetSendIcmpv6Redirect() const
 {
-    NS_LOG_FUNCTION(this);
     return m_sendIcmpv6Redirect;
 }
 
@@ -848,16 +829,12 @@
 Ptr<IpL4Protocol>
 Ipv6L3Protocol::GetProtocol(int protocolNumber) const
 {
-    NS_LOG_FUNCTION(this << protocolNumber);
-
     return GetProtocol(protocolNumber, -1);
 }
 
 Ptr<IpL4Protocol>
 Ipv6L3Protocol::GetProtocol(int protocolNumber, int32_t interfaceIndex) const
 {
-    NS_LOG_FUNCTION(this << protocolNumber << interfaceIndex);
-
     if (interfaceIndex >= 0)
     {
         // try the interface-specific protocol.
@@ -907,7 +884,6 @@
 Ptr<Icmpv6L4Protocol>
 Ipv6L3Protocol::GetIcmpv6() const
 {
-    NS_LOG_FUNCTION(this);
     Ptr<IpL4Protocol> protocol = GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber());
 
     if (protocol)
@@ -1126,12 +1102,8 @@
         }
     }
 
-    if (hdr.GetDestination().IsAllNodesMulticast())
-    {
-        LocalDeliver(packet, hdr, interface);
-        return;
-    }
-    else if (hdr.GetDestination().IsAllRoutersMulticast() && ipv6Interface->IsForwarding())
+    if (hdr.GetDestination().IsAllNodesMulticast() ||
+        (hdr.GetDestination().IsAllRoutersMulticast() && ipv6Interface->IsForwarding()))
     {
         LocalDeliver(packet, hdr, interface);
         return;
@@ -1562,32 +1534,37 @@
                 p->RemoveAtStart(nextHeaderPosition);
                 /* protocol->Receive (p, src, dst, incomingInterface); */
 
+                // Options have been processed, and the packet is good.
+                // We need to adjust the IP header fields
+                Ipv6Header newIpHeader = ip;
+                newIpHeader.SetNextHeader(nextHeader);
+                newIpHeader.SetPayloadLength(p->GetSize());
+
                 /* L4 protocol */
                 Ptr<Packet> copy = p->Copy();
 
-                m_localDeliverTrace(ip, p, iif);
+                m_localDeliverTrace(newIpHeader, p, iif);
 
-                IpL4Protocol::RxStatus status = protocol->Receive(p, ip, GetInterface(iif));
+                IpL4Protocol::RxStatus status =
+                    protocol->Receive(p, newIpHeader, GetInterface(iif));
 
                 switch (status)
                 {
                 case IpL4Protocol::RX_OK:
-                    break;
                 case IpL4Protocol::RX_CSUM_FAILED:
-                    break;
                 case IpL4Protocol::RX_ENDPOINT_CLOSED:
                     break;
                 case IpL4Protocol::RX_ENDPOINT_UNREACH:
-                    if (ip.GetDestination().IsMulticast())
+                    if (newIpHeader.GetDestination().IsMulticast())
                     {
                         /* do not rely on multicast address */
                         break;
                     }
 
-                    copy->AddHeader(ip);
+                    copy->AddHeader(newIpHeader);
                     GetIcmpv6()->SendErrorDestinationUnreachable(
                         copy,
-                        ip.GetSource(),
+                        newIpHeader.GetSource(),
                         Icmpv6Header::ICMPV6_PORT_UNREACHABLE);
                 }
             }
@@ -1768,8 +1745,6 @@
 bool
 Ipv6L3Protocol::IsRegisteredMulticastAddress(Ipv6Address address, uint32_t interface) const
 {
-    NS_LOG_FUNCTION(address << interface);
-
     Ipv6RegisteredMulticastAddressKey_t key = std::make_pair(address, interface);
     auto iter = m_multicastAddresses.find(key);
 
@@ -1779,8 +1754,6 @@
 bool
 Ipv6L3Protocol::IsRegisteredMulticastAddress(Ipv6Address address) const
 {
-    NS_LOG_FUNCTION(address);
-
     auto iter = m_multicastAddressesNoInterface.find(address);
 
     return iter != m_multicastAddressesNoInterface.end();
@@ -1845,7 +1818,6 @@
 bool
 Ipv6L3Protocol::GetStrongEndSystemModel() const
 {
-    NS_LOG_FUNCTION(this);
     return m_strongEndSystemModel;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv6-option-header.cc ns-3.42/src/internet/model/ipv6-option-header.cc
--- ns-3.41/src/internet/model/ipv6-option-header.cc	2024-02-09 14:44:07.933790200 -0800
+++ ns-3.42/src/internet/model/ipv6-option-header.cc	2024-05-29 15:29:46.964073200 -0700
@@ -124,7 +124,7 @@
 Ipv6OptionHeader::Alignment
 Ipv6OptionHeader::GetAlignment() const
 {
-    return (Alignment){1, 0};
+    return Alignment{1, 0};
 }
 
 NS_OBJECT_ENSURE_REGISTERED(Ipv6OptionPad1Header);
@@ -329,7 +329,7 @@
 Ipv6OptionHeader::Alignment
 Ipv6OptionJumbogramHeader::GetAlignment() const
 {
-    return (Alignment){4, 2}; // 4n+2
+    return Alignment{4, 2}; // 4n+2
 }
 
 NS_OBJECT_ENSURE_REGISTERED(Ipv6OptionRouterAlertHeader);
@@ -411,7 +411,7 @@
 Ipv6OptionHeader::Alignment
 Ipv6OptionRouterAlertHeader::GetAlignment() const
 {
-    return (Alignment){2, 0}; // 2n+0
+    return Alignment{2, 0}; // 2n+0
 }
 
 } /* namespace ns3 */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ipv6-static-routing.cc ns-3.42/src/internet/model/ipv6-static-routing.cc
--- ns-3.41/src/internet/model/ipv6-static-routing.cc	2024-02-09 14:44:07.933790200 -0800
+++ ns-3.42/src/internet/model/ipv6-static-routing.cc	2024-05-29 15:29:46.964073200 -0700
@@ -444,22 +444,18 @@
                 uint32_t interfaceIdx = route->GetInterface();
                 rtentry = Create<Ipv6Route>();
 
-                if (route->GetGateway().IsAny())
+                if (route->GetGateway().IsAny() || !route->GetDest().IsAny())
                 {
                     rtentry->SetSource(
                         m_ipv6->SourceAddressSelection(interfaceIdx, route->GetDest()));
                 }
-                else if (route->GetDest().IsAny()) /* default route */
+                else
                 {
+                    // Default route
                     rtentry->SetSource(m_ipv6->SourceAddressSelection(
                         interfaceIdx,
                         route->GetPrefixToUse().IsAny() ? dst : route->GetPrefixToUse()));
                 }
-                else
-                {
-                    rtentry->SetSource(
-                        m_ipv6->SourceAddressSelection(interfaceIdx, route->GetDest()));
-                }
 
                 rtentry->SetDestination(route->GetDest());
                 rtentry->SetGateway(route->GetGateway());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/loopback-net-device.cc ns-3.42/src/internet/model/loopback-net-device.cc
--- ns-3.41/src/internet/model/loopback-net-device.cc	2024-02-09 14:44:07.933790200 -0800
+++ ns-3.42/src/internet/model/loopback-net-device.cc	2024-05-29 15:29:46.964073200 -0700
@@ -58,11 +58,7 @@
 {
     NS_LOG_FUNCTION(packet << " " << protocol << " " << to << " " << from);
     NetDevice::PacketType packetType;
-    if (to == m_address)
-    {
-        packetType = NetDevice::PACKET_HOST;
-    }
-    else if (to.IsBroadcast())
+    if (to == m_address || to.IsBroadcast())
     {
         packetType = NetDevice::PACKET_HOST;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/rip.cc ns-3.42/src/internet/model/rip.cc
--- ns-3.41/src/internet/model/rip.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/rip.cc	2024-05-29 15:29:46.964073200 -0700
@@ -741,7 +741,7 @@
             route->SetRouteStatus(RipRoutingTableEntry::RIP_INVALID);
             route->SetRouteMetric(m_linkDown);
             route->SetRouteChanged(true);
-            if (it->second.IsRunning())
+            if (it->second.IsPending())
             {
                 it->second.Cancel();
             }
@@ -1241,11 +1241,8 @@
                         rte.SetRouteMetric(rtIter->first->GetRouteMetric());
                     }
                     rte.SetRouteTag(rtIter->first->GetRouteTag());
-                    if (m_splitHorizonStrategy == SPLIT_HORIZON && !splitHorizoning)
-                    {
-                        hdr.AddRte(rte);
-                    }
-                    else if (m_splitHorizonStrategy != SPLIT_HORIZON)
+                    if ((m_splitHorizonStrategy == SPLIT_HORIZON && !splitHorizoning) ||
+                        (m_splitHorizonStrategy != SPLIT_HORIZON))
                     {
                         hdr.AddRte(rte);
                     }
@@ -1278,7 +1275,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_nextTriggeredUpdate.IsRunning())
+    if (m_nextTriggeredUpdate.IsPending())
     {
         NS_LOG_LOGIC("Skipping Triggered Update due to cooldown");
         return;
@@ -1310,7 +1307,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_nextTriggeredUpdate.IsRunning())
+    if (m_nextTriggeredUpdate.IsPending())
     {
         m_nextTriggeredUpdate.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/ripng.cc ns-3.42/src/internet/model/ripng.cc
--- ns-3.41/src/internet/model/ripng.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/ripng.cc	2024-05-29 15:29:46.964073200 -0700
@@ -740,7 +740,7 @@
             route->SetRouteStatus(RipNgRoutingTableEntry::RIPNG_INVALID);
             route->SetRouteMetric(m_linkDown);
             route->SetRouteChanged(true);
-            if (it->second.IsRunning())
+            if (it->second.IsPending())
             {
                 it->second.Cancel();
             }
@@ -1242,11 +1242,8 @@
                         rte.SetRouteMetric(rtIter->first->GetRouteMetric());
                     }
                     rte.SetRouteTag(rtIter->first->GetRouteTag());
-                    if (m_splitHorizonStrategy == SPLIT_HORIZON && !splitHorizoning)
-                    {
-                        hdr.AddRte(rte);
-                    }
-                    else if (m_splitHorizonStrategy != SPLIT_HORIZON)
+                    if ((m_splitHorizonStrategy == SPLIT_HORIZON && !splitHorizoning) ||
+                        (m_splitHorizonStrategy != SPLIT_HORIZON))
                     {
                         hdr.AddRte(rte);
                     }
@@ -1279,7 +1276,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_nextTriggeredUpdate.IsRunning())
+    if (m_nextTriggeredUpdate.IsPending())
     {
         NS_LOG_LOGIC("Skipping Triggered Update due to cooldown");
         return;
@@ -1311,7 +1308,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_nextTriggeredUpdate.IsRunning())
+    if (m_nextTriggeredUpdate.IsPending())
     {
         m_nextTriggeredUpdate.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-bbr.cc ns-3.42/src/internet/model/tcp-bbr.cc
--- ns-3.41/src/internet/model/tcp-bbr.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-bbr.cc	2024-05-29 15:29:46.964073200 -0700
@@ -58,7 +58,7 @@
             .AddAttribute("RttWindowLength",
                           "Length of RTT windowed filter",
                           TimeValue(Seconds(10)),
-                          MakeTimeAccessor(&TcpBbr::m_rtPropFilterLen),
+                          MakeTimeAccessor(&TcpBbr::m_minRttFilterLen),
                           MakeTimeChecker())
             .AddAttribute("ProbeRttDuration",
                           "Time to be spent in PROBE_RTT phase",
@@ -107,18 +107,17 @@
       m_targetCWnd(sock.m_targetCWnd),
       m_fullBandwidth(sock.m_fullBandwidth),
       m_fullBandwidthCount(sock.m_fullBandwidthCount),
-      m_rtProp(Time::Max()),
+      m_minRtt(Time::Max()),
       m_sendQuantum(sock.m_sendQuantum),
       m_cycleStamp(sock.m_cycleStamp),
       m_cycleIndex(sock.m_cycleIndex),
-      m_rtPropExpired(sock.m_rtPropExpired),
-      m_rtPropFilterLen(sock.m_rtPropFilterLen),
-      m_rtPropStamp(sock.m_rtPropStamp),
+      m_minRttExpired(sock.m_minRttExpired),
+      m_minRttFilterLen(sock.m_minRttFilterLen),
+      m_minRttStamp(sock.m_minRttStamp),
       m_isInitialized(sock.m_isInitialized),
       m_uv(sock.m_uv),
       m_delivered(sock.m_delivered),
       m_appLimited(sock.m_appLimited),
-      m_txItemDelivered(sock.m_txItemDelivered),
       m_extraAckedGain(sock.m_extraAckedGain),
       m_extraAckedWinRtt(sock.m_extraAckedWinRtt),
       m_extraAckedWinRttLength(sock.m_extraAckedWinRttLength),
@@ -220,6 +219,7 @@
 {
     NS_LOG_FUNCTION(this << tcb << gain);
     DataRate rate(gain * m_maxBwFilter.GetBest().GetBitRate());
+    rate *= (1.f - m_pacingMargin);
     rate = std::min(rate, tcb->m_maxPacingRate);
 
     if (!m_hasSeenRtt && tcb->m_minRtt != Time::Max())
@@ -237,12 +237,12 @@
 TcpBbr::InFlight(Ptr<TcpSocketState> tcb, double gain)
 {
     NS_LOG_FUNCTION(this << tcb << gain);
-    if (m_rtProp == Time::Max())
+    if (m_minRtt == Time::Max())
     {
         return tcb->m_initialCWnd * tcb->m_segmentSize;
     }
     double quanta = 3 * m_sendQuantum;
-    double estimatedBdp = m_maxBwFilter.GetBest() * m_rtProp / 8.0;
+    double estimatedBdp = m_maxBwFilter.GetBest() * m_minRtt / 8.0;
 
     if (m_state == BbrMode_t::BBR_PROBE_BW && m_cycleIndex == 0)
     {
@@ -264,7 +264,7 @@
 TcpBbr::IsNextCyclePhase(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs)
 {
     NS_LOG_FUNCTION(this << tcb << rs);
-    bool isFullLength = (Simulator::Now() - m_cycleStamp) > m_rtProp;
+    bool isFullLength = (Simulator::Now() - m_cycleStamp) > m_minRtt;
     if (m_pacingGain == 1)
     {
         return isFullLength;
@@ -355,11 +355,11 @@
 TcpBbr::UpdateRTprop(Ptr<TcpSocketState> tcb)
 {
     NS_LOG_FUNCTION(this << tcb);
-    m_rtPropExpired = Simulator::Now() > (m_rtPropStamp + m_rtPropFilterLen);
-    if (tcb->m_lastRtt >= Seconds(0) && (tcb->m_lastRtt <= m_rtProp || m_rtPropExpired))
+    m_minRttExpired = Simulator::Now() > (m_minRttStamp + m_minRttFilterLen);
+    if (tcb->m_lastRtt >= Seconds(0) && (tcb->m_lastRtt <= m_minRtt || m_minRttExpired))
     {
-        m_rtProp = tcb->m_lastRtt;
-        m_rtPropStamp = Simulator::Now();
+        m_minRtt = tcb->m_lastRtt;
+        m_minRttStamp = Simulator::Now();
     }
 }
 
@@ -429,7 +429,7 @@
         }
         if (m_probeRttRoundDone && Simulator::Now() > m_probeRttDoneStamp)
         {
-            m_rtPropStamp = Simulator::Now();
+            m_minRttStamp = Simulator::Now();
             RestoreCwnd(tcb);
             ExitProbeRTT();
         }
@@ -440,7 +440,7 @@
 TcpBbr::CheckProbeRTT(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs)
 {
     NS_LOG_FUNCTION(this << tcb);
-    if (m_state != BbrMode_t::BBR_PROBE_RTT && m_rtPropExpired && !m_idleRestart)
+    if (m_state != BbrMode_t::BBR_PROBE_RTT && m_minRttExpired && !m_idleRestart)
     {
         EnterProbeRTT();
         SaveCwnd(tcb);
@@ -611,11 +611,11 @@
 }
 
 void
-TcpBbr::UpdateBtlBw(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs)
+TcpBbr::UpdateBottleneckBandwidth(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs)
 {
     NS_LOG_FUNCTION(this << tcb << rs);
 
-    if (rs.m_deliveryRate == 0)
+    if (rs.m_delivered < 0 || rs.m_interval.IsZero())
     {
         return;
     }
@@ -632,7 +632,7 @@
 TcpBbr::UpdateModelAndState(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs)
 {
     NS_LOG_FUNCTION(this << tcb << rs);
-    UpdateBtlBw(tcb, rs);
+    UpdateBottleneckBandwidth(tcb, rs);
     UpdateAckAggregation(tcb, rs);
     CheckCyclePhase(tcb, rs);
     CheckFullPipe(rs);
@@ -700,7 +700,6 @@
 {
     NS_LOG_FUNCTION(this << tcb << rs);
     m_delivered = rc.m_delivered;
-    m_txItemDelivered = rc.m_txItemDelivered;
     UpdateModelAndState(tcb, rs);
     UpdateControlParameters(tcb, rs);
 }
@@ -712,8 +711,8 @@
     if (newState == TcpSocketState::CA_OPEN && !m_isInitialized)
     {
         NS_LOG_DEBUG("CongestionStateSet triggered to CA_OPEN :: " << newState);
-        m_rtProp = tcb->m_lastRtt.Get() != Time::Max() ? tcb->m_lastRtt.Get() : Time::Max();
-        m_rtPropStamp = Simulator::Now();
+        m_minRtt = tcb->m_lastRtt.Get() != Time::Max() ? tcb->m_lastRtt.Get() : Time::Max();
+        m_minRttStamp = Simulator::Now();
         m_priorCwnd = tcb->m_cWnd;
         tcb->m_ssThresh = tcb->m_initialSsThresh;
         m_targetCWnd = tcb->m_cWnd;
@@ -772,7 +771,7 @@
         {
             if (m_probeRttRoundDone && Simulator::Now() > m_probeRttDoneStamp)
             {
-                m_rtPropStamp = Simulator::Now();
+                m_minRttStamp = Simulator::Now();
                 RestoreCwnd(tcb);
                 ExitProbeRTT();
             }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-bbr.h ns-3.42/src/internet/model/tcp-bbr.h
--- ns-3.41/src/internet/model/tcp-bbr.h	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-bbr.h	2024-05-29 15:29:46.964073200 -0700
@@ -293,7 +293,7 @@
      * \param tcb the socket state.
      * \param rs rate sample.
      */
-    void UpdateBtlBw(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs);
+    void UpdateBottleneckBandwidth(Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample& rs);
 
     /**
      * \brief Updates control parameters congestion windowm, pacing rate, send quantum.
@@ -373,25 +373,23 @@
     uint32_t m_targetCWnd{0}; //!< Target value for congestion window, adapted to the estimated BDP
     DataRate m_fullBandwidth{0};      //!< Value of full bandwidth recorded
     uint32_t m_fullBandwidthCount{0}; //!< Count of full bandwidth recorded consistently
-    Time m_rtProp{
+    Time m_minRtt{
         Time::Max()}; //!< Estimated two-way round-trip propagation delay of the path, estimated
                       //!< from the windowed minimum recent round-trip delay sample.
     uint32_t m_sendQuantum{
         0}; //!< The maximum size of a data aggregate scheduled and transmitted together
     Time m_cycleStamp{Seconds(0)};       //!< Last time gain cycle updated
     uint32_t m_cycleIndex{0};            //!< Current index of gain cycle
-    bool m_rtPropExpired{false};         //!< A boolean recording whether the BBR.RTprop has expired
-    Time m_rtPropFilterLen{Seconds(10)}; //!< A constant specifying the length of the RTProp min
+    bool m_minRttExpired{false};         //!< A boolean recording whether the BBR.RTprop has expired
+    Time m_minRttFilterLen{Seconds(10)}; //!< A constant specifying the length of the RTProp min
                                          //!< filter window, default 10 secs.
-    Time m_rtPropStamp{
+    Time m_minRttStamp{
         Seconds(0)}; //!< The wall clock time at which the current BBR.RTProp sample was obtained
-    bool m_isInitialized{false}; //!< Set to true after first time initializtion variables
+    bool m_isInitialized{false}; //!< Set to true after first time initialization variables
     Ptr<UniformRandomVariable> m_uv{nullptr}; //!< Uniform Random Variable
     uint64_t m_delivered{0}; //!< The total amount of data in bytes delivered so far
     uint32_t m_appLimited{
         0}; //!< The index of the last transmitted packet marked as application-limited
-    uint32_t m_txItemDelivered{
-        0}; //!< The number of bytes already delivered at the time of new packet transmission
     uint32_t m_extraAckedGain{1};         //!< Gain factor for adding extra ack to cwnd
     uint32_t m_extraAcked[2]{0, 0};       //!< Maximum excess data acked in epoch
     uint32_t m_extraAckedWinRtt{0};       //!< Age of extra acked in rtt
@@ -402,6 +400,8 @@
     Time m_ackEpochTime{Seconds(0)}; //!< Starting of ACK sampling epoch time
     uint32_t m_ackEpochAcked{0};     //!< Bytes ACked in sampling epoch
     bool m_hasSeenRtt{false};        //!< Have we seen RTT sample yet?
+    double m_pacingMargin{0.01}; //!< BBR intentionally reduces the pacing rate by 1% to drain any
+                                 //!< standing queues. See `bbr_rate_bytes_per_sec` in Linux.
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-cubic.cc ns-3.42/src/internet/model/tcp-cubic.cc
--- ns-3.41/src/internet/model/tcp-cubic.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-cubic.cc	2024-05-29 15:29:46.964073200 -0700
@@ -189,6 +189,13 @@
 {
     NS_LOG_FUNCTION(this << tcb << segmentsAcked);
 
+    if (!tcb->m_isCwndLimited)
+    {
+        NS_LOG_DEBUG("No increase because current cwnd " << tcb->m_cWnd
+                                                         << " is not limiting the flow");
+        return;
+    }
+
     if (tcb->m_cWnd < tcb->m_ssThresh)
     {
         if (m_hystart && tcb->m_lastAckedSeq > m_endSeq)
@@ -490,7 +497,6 @@
 {
     NS_LOG_FUNCTION(this << tcb);
 
-    m_lastMaxCwnd = 0;
     m_bicOriginPoint = 0;
     m_bicK = 0;
     m_ackCnt = 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-dctcp.cc ns-3.42/src/internet/model/tcp-dctcp.cc
--- ns-3.41/src/internet/model/tcp-dctcp.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-dctcp.cc	2024-05-29 15:29:46.964073200 -0700
@@ -121,6 +121,7 @@
     tcb->m_useEcn = TcpSocketState::On;
     tcb->m_ecnMode = TcpSocketState::DctcpEcn;
     tcb->m_ectCodePoint = m_useEct0 ? TcpSocketState::Ect0 : TcpSocketState::Ect1;
+    SetSuppressIncreaseIfCwndLimited(false);
     m_initialized = true;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-highspeed.cc ns-3.42/src/internet/model/tcp-highspeed.cc
--- ns-3.41/src/internet/model/tcp-highspeed.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-highspeed.cc	2024-05-29 15:29:46.964073200 -0700
@@ -447,15 +447,14 @@
     {
         return 73;
     }
-    else
-    {
-        return 73;
-    }
+
+    return 73;
 }
 
 double
 TcpHighSpeed::TableLookupB(uint32_t w)
 {
+    // NOLINTBEGIN(bugprone-branch-clone)
     if (w <= 38)
     {
         return 0.50;
@@ -752,6 +751,7 @@
     {
         return 0.09;
     }
+    // NOLINTEND(bugprone-branch-clone)
 }
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-linux-reno.cc ns-3.42/src/internet/model/tcp-linux-reno.cc
--- ns-3.41/src/internet/model/tcp-linux-reno.cc	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-linux-reno.cc	2024-05-29 15:29:46.968073100 -0700
@@ -79,6 +79,13 @@
 {
     NS_LOG_FUNCTION(this << tcb << segmentsAcked);
 
+    if (m_suppressIncreaseIfCwndLimited && !tcb->m_isCwndLimited)
+    {
+        NS_LOG_DEBUG("No increase because current cwnd " << tcb->m_cWnd
+                                                         << " is not limiting the flow");
+        return;
+    }
+
     uint32_t w = tcb->m_cWnd / tcb->m_segmentSize;
 
     // Floor w to 1 if w == 0
@@ -150,4 +157,11 @@
     return CopyObject<TcpLinuxReno>(this);
 }
 
+void
+TcpLinuxReno::SetSuppressIncreaseIfCwndLimited(bool value)
+{
+    NS_LOG_FUNCTION(this << value);
+    m_suppressIncreaseIfCwndLimited = value;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-linux-reno.h ns-3.42/src/internet/model/tcp-linux-reno.h
--- ns-3.41/src/internet/model/tcp-linux-reno.h	2024-02-09 14:44:07.937790400 -0800
+++ ns-3.42/src/internet/model/tcp-linux-reno.h	2024-05-29 15:29:46.968073100 -0700
@@ -76,8 +76,25 @@
      */
     virtual void CongestionAvoidance(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked);
 
+    /**
+     * TcpSocketBase follows the Linux way of setting a flag 'isCwndLimited'
+     * when BytesInFlight() >= cwnd.  This flag, if true, will suppress
+     * additive increase window updates for this class.  However, some
+     * derived classes using the IncreaseWindow() method may not want this
+     * behavior, so this method exists to allow subclasses to set it to false.
+     *
+     * \param value Value to set whether the isCwndLimited condition
+     *        suppresses window updates
+     */
+    void SetSuppressIncreaseIfCwndLimited(bool value);
+
   private:
     uint32_t m_cWndCnt{0}; //!< Linear increase counter
+    // The below flag exists for classes derived from TcpLinuxReno (such as
+    // TcpDctcp) that may not want to suppress cwnd increase, unlike Linux's
+    // tcp_reno_cong_avoid()
+    bool m_suppressIncreaseIfCwndLimited{
+        true}; //!< Suppress window increase if TCP is not cwnd limited
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-rate-ops.cc ns-3.42/src/internet/model/tcp-rate-ops.cc
--- ns-3.41/src/internet/model/tcp-rate-ops.cc	2024-02-09 14:44:07.941790300 -0800
+++ ns-3.42/src/internet/model/tcp-rate-ops.cc	2024-05-29 15:29:46.968073100 -0700
@@ -106,7 +106,7 @@
 
     /* Normally we expect m_interval >= minRtt.
      * Note that rate may still be over-estimated when a spuriously
-     * retransmistted skb was first (s)acked because "interval_us"
+     * retransmitted skb was first (s)acked because "interval_us"
      * is under-estimated (up to an RTT). However continuously
      * measuring the delivery rate during loss recovery is crucial
      * for connections suffer heavy or prolonged losses.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-recovery-ops.h ns-3.42/src/internet/model/tcp-recovery-ops.h
--- ns-3.41/src/internet/model/tcp-recovery-ops.h	2024-02-09 14:44:07.941790300 -0800
+++ ns-3.42/src/internet/model/tcp-recovery-ops.h	2024-05-29 15:29:46.968073100 -0700
@@ -95,7 +95,7 @@
      * The function is called when the TcpSocketState is changed to CA_RECOVERY.
      *
      * \param tcb internal congestion state
-     * \param dupAckCount duplicate acknowldgement count
+     * \param dupAckCount duplicate acknowledgement count
      * \param unAckDataCount total bytes of data unacknowledged
      * \param deliveredBytes bytes (S)ACKed in the last (S)ACK
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-socket-base.cc ns-3.42/src/internet/model/tcp-socket-base.cc
--- ns-3.41/src/internet/model/tcp-socket-base.cc	2024-02-09 14:44:07.941790300 -0800
+++ ns-3.42/src/internet/model/tcp-socket-base.cc	2024-05-29 15:29:46.968073100 -0700
@@ -575,7 +575,6 @@
         InetSocketAddress transport = InetSocketAddress::ConvertFrom(address);
         Ipv4Address ipv4 = transport.GetIpv4();
         uint16_t port = transport.GetPort();
-        SetIpTos(transport.GetTos());
         if (ipv4 == Ipv4Address::GetAny() && port == 0)
         {
             m_endPoint = m_tcp->Allocate();
@@ -690,7 +689,6 @@
         }
         InetSocketAddress transport = InetSocketAddress::ConvertFrom(address);
         m_endPoint->SetPeer(transport.GetIpv4(), transport.GetPort());
-        SetIpTos(transport.GetTos());
         m_endPoint6 = nullptr;
 
         // Get the appropriate local address and port number from the routing protocol and set up
@@ -871,7 +869,7 @@
         if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow() > 0)
         { // Try to send the data out: Add a little step to allow the application
             // to fill the buffer
-            if (!m_sendPendingDataEvent.IsRunning())
+            if (!m_sendPendingDataEvent.IsPending())
             {
                 m_sendPendingDataEvent = Simulator::Schedule(TimeStep(1),
                                                              &TcpSocketBase::SendPendingData,
@@ -1138,7 +1136,7 @@
         NotifyNormalClose();
         m_closeNotified = true;
     }
-    if (m_lastAckEvent.IsRunning())
+    if (m_lastAckEvent.IsPending())
     {
         m_lastAckEvent.Cancel();
     }
@@ -1475,7 +1473,7 @@
         break;
     }
 
-    if (m_rWnd.Get() != 0 && m_persistEvent.IsRunning())
+    if (m_rWnd.Get() != 0 && m_persistEvent.IsPending())
     { // persist probes end, the other end has increased the window
         NS_ASSERT(m_connected);
         NS_LOG_LOGIC(this << " Leaving zerowindow persist state");
@@ -1538,13 +1536,13 @@
             ReceivedAck(packet, tcpHeader);
         }
     }
-    else if (tcpflags == TcpHeader::SYN)
-    { // Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
-      // respond with a SYN+ACK. But it is not a legal state transition as of
-      // RFC793. Thus this is ignored.
-    }
-    else if (tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
-    { // No action for received SYN+ACK, it is probably a duplicated packet
+    else if (tcpflags == TcpHeader::SYN || tcpflags == (TcpHeader::SYN | TcpHeader::ACK))
+    {
+        // (a) Received SYN, old NS-3 behaviour is to set state to SYN_RCVD and
+        // respond with a SYN+ACK. But it is not a legal state transition as of
+        // RFC793. Thus this is ignored.
+
+        // (b) No action for received SYN+ACK, it is probably a duplicated packet
     }
     else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
     { // Received FIN or FIN+ACK, bring down this socket nicely
@@ -3240,6 +3238,12 @@
                      << m_endPoint6->GetPeerAddress() << ". Header " << header);
     }
 
+    // Signal to congestion control whether the cwnd is fully used
+    // This is a simple version of Linux tcp_cwnd_validate() but following
+    // the principle implemented in Linux that limits the updating of cwnd
+    // (in the congestion controls) when flight size is >= cwnd
+    m_tcb->m_isCwndLimited = (BytesInFlight() >= m_tcb->m_cWnd);
+
     UpdateRttHistory(seq, sz, isRetransmission);
 
     // Update bytes sent during recovery phase
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-socket-state.cc ns-3.42/src/internet/model/tcp-socket-state.cc
--- ns-3.41/src/internet/model/tcp-socket-state.cc	2024-02-09 14:44:07.941790300 -0800
+++ ns-3.42/src/internet/model/tcp-socket-state.cc	2024-05-29 15:29:46.968073100 -0700
@@ -119,6 +119,7 @@
       m_paceInitialWindow(other.m_paceInitialWindow),
       m_minRtt(other.m_minRtt),
       m_bytesInFlight(other.m_bytesInFlight),
+      m_isCwndLimited(other.m_isCwndLimited),
       m_lastRtt(other.m_lastRtt),
       m_ecnMode(other.m_ecnMode),
       m_useEcn(other.m_useEcn),
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-socket-state.h ns-3.42/src/internet/model/tcp-socket-state.h
--- ns-3.41/src/internet/model/tcp-socket-state.h	2024-02-09 14:44:07.941790300 -0800
+++ ns-3.42/src/internet/model/tcp-socket-state.h	2024-05-29 15:29:46.968073100 -0700
@@ -207,6 +207,7 @@
     Time m_minRtt{Time::Max()}; //!< Minimum RTT observed throughout the connection
 
     TracedValue<uint32_t> m_bytesInFlight{0};  //!< Bytes in flight
+    bool m_isCwndLimited{false};               //!< Whether throughput is limited by cwnd
     TracedValue<Time> m_lastRtt{Seconds(0.0)}; //!< Last RTT sample collected
 
     Ptr<TcpRxBuffer> m_rxBuffer; //!< Rx buffer (reordering buffer)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/tcp-tx-buffer.cc ns-3.42/src/internet/model/tcp-tx-buffer.cc
--- ns-3.41/src/internet/model/tcp-tx-buffer.cc	2024-02-09 14:44:07.941790300 -0800
+++ ns-3.42/src/internet/model/tcp-tx-buffer.cc	2024-05-29 15:29:46.968073100 -0700
@@ -866,8 +866,8 @@
 
     NS_ASSERT((*(m_sentList.begin()))->m_sacked == false);
     NS_ASSERT_MSG(m_sentSize >= m_sackedOut + m_lostOut, *this);
-    // NS_ASSERT (list.size () == 0 || modified);   // Assert for duplicated SACK or
-    //  impossiblity to map the option into the sent blocks
+    // Assert for duplicated SACK or impossibility to map the option into the sent blocks
+    // NS_ASSERT (list.size () == 0 || modified);
     ConsistencyCheck();
     return bytesSacked;
 }
@@ -1103,14 +1103,10 @@
         {
             bool isLost = IsLostRFC(beginOfCurrentPkt, it);
             // (a) If IsLost (S1) returns false: Pipe is incremented by 1 octet.
-            if (!isLost)
-            {
-                size += item->m_packet->GetSize();
-            }
             // (b) If S1 <= HighRxt: Pipe is incremented by 1 octet.
             // (NOTE: we use the m_retrans flag instead of keeping and updating
             // another variable). Only if the item is not marked as lost
-            else if (item->m_retrans)
+            if (!isLost || item->m_retrans)
             {
                 size += item->m_packet->GetSize();
             }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/udp-header.cc ns-3.42/src/internet/model/udp-header.cc
--- ns-3.41/src/internet/model/udp-header.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/model/udp-header.cc	2024-05-29 15:29:46.968073100 -0700
@@ -189,6 +189,12 @@
 
             i = start;
             i.Next(6);
+
+            // RFC 768: If the computed checksum is zero, it is transmitted as all ones
+            if (checksum == 0)
+            {
+                checksum = 0xffff;
+            }
             i.WriteU16(checksum);
         }
     }
@@ -207,7 +213,24 @@
     m_payloadSize = i.ReadNtohU16() - GetSerializedSize();
     m_checksum = i.ReadU16();
 
-    if (m_calcChecksum)
+    // RFC 768: An all zero transmitted checksum value means that the
+    // transmitter generated  no checksum (for debugging or for higher
+    // level protocols that don't care).
+    //
+    // This is common in IPv4, while IPv6 requires UDP to use its checksum.
+    //
+    // As strange as it might sound, flipping from 0x0000 to 0xffff does not
+    // change anything in the verification.
+    //
+    // According to RFC 1141, the following holds:
+    // ~C' = ~(C + (-m) + m') = ~C + (m - m') = ~C + m + ~m'
+    // If ~C (the original CRC) is zero, m (the CRC field) is zero, and m' is 0xffff,
+    // then, according to the formula, we have that ~C' is zero.
+    // I.e., changing the CRC from 0 to 0xffff has no effect on the Rx verification.
+    //
+    // Fun fact: if you take an IPv4 header with an Identification field set to zero
+    // and you change it to 0xffff, the checksum will not change (~_^)
+    if (m_calcChecksum && m_checksum)
     {
         uint16_t headerChecksum = CalculateHeaderChecksum(start.GetSize());
         i = start;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/model/udp-socket-impl.cc ns-3.42/src/internet/model/udp-socket-impl.cc
--- ns-3.41/src/internet/model/udp-socket-impl.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/model/udp-socket-impl.cc	2024-05-29 15:29:46.968073100 -0700
@@ -280,7 +280,6 @@
         InetSocketAddress transport = InetSocketAddress::ConvertFrom(address);
         Ipv4Address ipv4 = transport.GetIpv4();
         uint16_t port = transport.GetPort();
-        SetIpTos(transport.GetTos());
         if (ipv4 == Ipv4Address::GetAny() && port == 0)
         {
             m_endPoint = m_udp->Allocate();
@@ -416,7 +415,6 @@
         InetSocketAddress transport = InetSocketAddress::ConvertFrom(address);
         m_defaultAddress = Address(transport.GetIpv4());
         m_defaultPort = transport.GetPort();
-        SetIpTos(transport.GetTos());
         m_connected = true;
         NotifyConnectionSucceeded();
     }
@@ -839,8 +837,7 @@
         InetSocketAddress transport = InetSocketAddress::ConvertFrom(address);
         Ipv4Address ipv4 = transport.GetIpv4();
         uint16_t port = transport.GetPort();
-        uint8_t tos = transport.GetTos();
-        return DoSendTo(p, ipv4, port, tos);
+        return DoSendTo(p, ipv4, port, GetIpTos());
     }
     else if (Inet6SocketAddress::IsMatchingType(address))
     {
@@ -931,9 +928,7 @@
     if (Ipv4Address::IsMatchingType(m_defaultAddress))
     {
         Ipv4Address addr = Ipv4Address::ConvertFrom(m_defaultAddress);
-        InetSocketAddress inet(addr, m_defaultPort);
-        inet.SetTos(GetIpTos());
-        address = inet;
+        address = InetSocketAddress(addr, m_defaultPort);
     }
     else if (Ipv6Address::IsMatchingType(m_defaultAddress))
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/global-route-manager-impl-test-suite.cc ns-3.42/src/internet/test/global-route-manager-impl-test-suite.cc
--- ns-3.41/src/internet/test/global-route-manager-impl-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/global-route-manager-impl-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -229,9 +229,9 @@
 };
 
 GlobalRouteManagerImplTestSuite::GlobalRouteManagerImplTestSuite()
-    : TestSuite("global-route-manager-impl", UNIT)
+    : TestSuite("global-route-manager-impl", Type::UNIT)
 {
-    AddTestCase(new GlobalRouteManagerImplTestCase(), TestCase::QUICK);
+    AddTestCase(new GlobalRouteManagerImplTestCase(), TestCase::Duration::QUICK);
 }
 
 static GlobalRouteManagerImplTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/icmp-test.cc ns-3.42/src/internet/test/icmp-test.cc
--- ns-3.41/src/internet/test/icmp-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/icmp-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -664,12 +664,12 @@
 };
 
 IcmpTestSuite::IcmpTestSuite()
-    : TestSuite("icmp", UNIT)
+    : TestSuite("icmp", Type::UNIT)
 {
-    AddTestCase(new IcmpEchoReplyTestCase, TestCase::QUICK);
-    AddTestCase(new IcmpTimeExceedTestCase, TestCase::QUICK);
-    AddTestCase(new IcmpV6EchoReplyTestCase, TestCase::QUICK);
-    AddTestCase(new IcmpV6TimeExceedTestCase, TestCase::QUICK);
+    AddTestCase(new IcmpEchoReplyTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new IcmpTimeExceedTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new IcmpV6EchoReplyTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new IcmpV6TimeExceedTestCase, TestCase::Duration::QUICK);
 }
 
 static IcmpTestSuite icmpTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/internet-stack-helper-test-suite.cc ns-3.42/src/internet/test/internet-stack-helper-test-suite.cc
--- ns-3.41/src/internet/test/internet-stack-helper-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/internet-stack-helper-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -148,9 +148,9 @@
 {
   public:
     InternetStackHelperTestSuite()
-        : TestSuite("internet-stack-helper", UNIT)
+        : TestSuite("internet-stack-helper", Type::UNIT)
     {
-        AddTestCase(new InternetStackHelperTestCase(), TestCase::QUICK);
+        AddTestCase(new InternetStackHelperTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-address-generator-test-suite.cc ns-3.42/src/internet/test/ipv4-address-generator-test-suite.cc
--- ns-3.41/src/internet/test/ipv4-address-generator-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-address-generator-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -363,13 +363,13 @@
 };
 
 Ipv4AddressGeneratorTestSuite::Ipv4AddressGeneratorTestSuite()
-    : TestSuite("ipv4-address-generator", UNIT)
+    : TestSuite("ipv4-address-generator", Type::UNIT)
 {
-    AddTestCase(new NetworkNumberAllocatorTestCase(), TestCase::QUICK);
-    AddTestCase(new AddressAllocatorTestCase(), TestCase::QUICK);
-    AddTestCase(new NetworkAndAddressTestCase(), TestCase::QUICK);
-    AddTestCase(new ExampleAddressGeneratorTestCase(), TestCase::QUICK);
-    AddTestCase(new AddressCollisionTestCase(), TestCase::QUICK);
+    AddTestCase(new NetworkNumberAllocatorTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new AddressAllocatorTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new NetworkAndAddressTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new ExampleAddressGeneratorTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new AddressCollisionTestCase(), TestCase::Duration::QUICK);
 }
 
 static Ipv4AddressGeneratorTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-address-helper-test-suite.cc ns-3.42/src/internet/test/ipv4-address-helper-test-suite.cc
--- ns-3.41/src/internet/test/ipv4-address-helper-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-address-helper-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -289,12 +289,12 @@
 };
 
 Ipv4AddressHelperTestSuite::Ipv4AddressHelperTestSuite()
-    : TestSuite("ipv4-address-helper", UNIT)
+    : TestSuite("ipv4-address-helper", Type::UNIT)
 {
-    AddTestCase(new NetworkAllocatorHelperTestCase(), TestCase::QUICK);
-    AddTestCase(new AddressAllocatorHelperTestCase(), TestCase::QUICK);
-    AddTestCase(new ResetAllocatorHelperTestCase(), TestCase::QUICK);
-    AddTestCase(new IpAddressHelperTestCasev4(), TestCase::QUICK);
+    AddTestCase(new NetworkAllocatorHelperTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new AddressAllocatorHelperTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new ResetAllocatorHelperTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new IpAddressHelperTestCasev4(), TestCase::Duration::QUICK);
 }
 
 static Ipv4AddressHelperTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-deduplication-test.cc ns-3.42/src/internet/test/ipv4-deduplication-test.cc
--- ns-3.41/src/internet/test/ipv4-deduplication-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-deduplication-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -557,12 +557,12 @@
 };
 
 Ipv4DeduplicationTestSuite::Ipv4DeduplicationTestSuite()
-    : TestSuite("ipv4-deduplication", UNIT)
+    : TestSuite("ipv4-deduplication", Type::UNIT)
 {
-    AddTestCase(new Ipv4DeduplicationTest(true), TestCase::QUICK);
-    AddTestCase(new Ipv4DeduplicationTest(false), TestCase::QUICK);
+    AddTestCase(new Ipv4DeduplicationTest(true), TestCase::Duration::QUICK);
+    AddTestCase(new Ipv4DeduplicationTest(false), TestCase::Duration::QUICK);
     // degenerate case is enabled RFC but with too short an expiry
-    AddTestCase(new Ipv4DeduplicationTest(true, MicroSeconds(50)), TestCase::QUICK);
+    AddTestCase(new Ipv4DeduplicationTest(true, MicroSeconds(50)), TestCase::Duration::QUICK);
 }
 
 static Ipv4DeduplicationTestSuite
@@ -737,9 +737,9 @@
 };
 
 Ipv4DeduplicationPerformanceTestSuite::Ipv4DeduplicationPerformanceTestSuite()
-    : TestSuite("ipv4-deduplication-performance", PERFORMANCE)
+    : TestSuite("ipv4-deduplication-performance", Type::PERFORMANCE)
 {
-    AddTestCase(new Ipv4DeduplicationPerformanceTest, TestCase::EXTENSIVE);
+    AddTestCase(new Ipv4DeduplicationPerformanceTest, TestCase::Duration::EXTENSIVE);
 }
 
 static Ipv4DeduplicationPerformanceTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-forwarding-test.cc ns-3.42/src/internet/test/ipv4-forwarding-test.cc
--- ns-3.41/src/internet/test/ipv4-forwarding-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-forwarding-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -238,9 +238,9 @@
 };
 
 Ipv4ForwardingTestSuite::Ipv4ForwardingTestSuite()
-    : TestSuite("ipv4-forwarding", UNIT)
+    : TestSuite("ipv4-forwarding", Type::UNIT)
 {
-    AddTestCase(new Ipv4ForwardingTest, TestCase::QUICK);
+    AddTestCase(new Ipv4ForwardingTest, TestCase::Duration::QUICK);
 }
 
 static Ipv4ForwardingTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-fragmentation-test.cc ns-3.42/src/internet/test/ipv4-fragmentation-test.cc
--- ns-3.41/src/internet/test/ipv4-fragmentation-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-fragmentation-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -587,10 +587,10 @@
 };
 
 Ipv4FragmentationTestSuite::Ipv4FragmentationTestSuite()
-    : TestSuite("ipv4-fragmentation", UNIT)
+    : TestSuite("ipv4-fragmentation", Type::UNIT)
 {
-    AddTestCase(new Ipv4FragmentationTest(false), TestCase::QUICK);
-    AddTestCase(new Ipv4FragmentationTest(true), TestCase::QUICK);
+    AddTestCase(new Ipv4FragmentationTest(false), TestCase::Duration::QUICK);
+    AddTestCase(new Ipv4FragmentationTest(true), TestCase::Duration::QUICK);
 }
 
 static Ipv4FragmentationTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-global-routing-test-suite.cc ns-3.42/src/internet/test/ipv4-global-routing-test-suite.cc
--- ns-3.41/src/internet/test/ipv4-global-routing-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-global-routing-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -1323,16 +1323,16 @@
 };
 
 Ipv4GlobalRoutingTestSuite::Ipv4GlobalRoutingTestSuite()
-    : TestSuite("ipv4-global-routing", UNIT)
+    : TestSuite("ipv4-global-routing", Type::UNIT)
 {
-    AddTestCase(new LinkTest, TestCase::QUICK);
-    AddTestCase(new LanTest, TestCase::QUICK);
-    AddTestCase(new TwoLinkTest, TestCase::QUICK);
-    AddTestCase(new TwoLanTest, TestCase::QUICK);
-    AddTestCase(new BridgeTest, TestCase::QUICK);
-    AddTestCase(new TwoBridgeTest, TestCase::QUICK);
-    AddTestCase(new Ipv4DynamicGlobalRoutingTestCase, TestCase::QUICK);
-    AddTestCase(new Ipv4GlobalRoutingSlash32TestCase, TestCase::QUICK);
+    AddTestCase(new LinkTest, TestCase::Duration::QUICK);
+    AddTestCase(new LanTest, TestCase::Duration::QUICK);
+    AddTestCase(new TwoLinkTest, TestCase::Duration::QUICK);
+    AddTestCase(new TwoLanTest, TestCase::Duration::QUICK);
+    AddTestCase(new BridgeTest, TestCase::Duration::QUICK);
+    AddTestCase(new TwoBridgeTest, TestCase::Duration::QUICK);
+    AddTestCase(new Ipv4DynamicGlobalRoutingTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new Ipv4GlobalRoutingSlash32TestCase, TestCase::Duration::QUICK);
 }
 
 static Ipv4GlobalRoutingTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-header-test.cc ns-3.42/src/internet/test/ipv4-header-test.cc
--- ns-3.41/src/internet/test/ipv4-header-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-header-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -299,9 +299,9 @@
 {
   public:
     Ipv4HeaderTestSuite()
-        : TestSuite("ipv4-header", UNIT)
+        : TestSuite("ipv4-header", Type::UNIT)
     {
-        AddTestCase(new Ipv4HeaderTest, TestCase::QUICK);
+        AddTestCase(new Ipv4HeaderTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-list-routing-test-suite.cc ns-3.42/src/internet/test/ipv4-list-routing-test-suite.cc
--- ns-3.41/src/internet/test/ipv4-list-routing-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-list-routing-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -209,10 +209,10 @@
 {
   public:
     Ipv4ListRoutingTestSuite()
-        : TestSuite("ipv4-list-routing", UNIT)
+        : TestSuite("ipv4-list-routing", Type::UNIT)
     {
-        AddTestCase(new Ipv4ListRoutingPositiveTestCase(), TestCase::QUICK);
-        AddTestCase(new Ipv4ListRoutingNegativeTestCase(), TestCase::QUICK);
+        AddTestCase(new Ipv4ListRoutingPositiveTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Ipv4ListRoutingNegativeTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-packet-info-tag-test-suite.cc ns-3.42/src/internet/test/ipv4-packet-info-tag-test-suite.cc
--- ns-3.41/src/internet/test/ipv4-packet-info-tag-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-packet-info-tag-test-suite.cc	2024-05-29 15:29:46.968073100 -0700
@@ -220,9 +220,9 @@
 };
 
 Ipv4PacketInfoTagTestSuite::Ipv4PacketInfoTagTestSuite()
-    : TestSuite("ipv4-packet-info-tag", UNIT)
+    : TestSuite("ipv4-packet-info-tag", Type::UNIT)
 {
-    AddTestCase(new Ipv4PacketInfoTagTest(), TestCase::QUICK);
+    AddTestCase(new Ipv4PacketInfoTagTest(), TestCase::Duration::QUICK);
 }
 
 static Ipv4PacketInfoTagTestSuite g_packetinfotagTests; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-raw-test.cc ns-3.42/src/internet/test/ipv4-raw-test.cc
--- ns-3.41/src/internet/test/ipv4-raw-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-raw-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -378,9 +378,9 @@
 {
   public:
     Ipv4RawTestSuite()
-        : TestSuite("ipv4-raw", UNIT)
+        : TestSuite("ipv4-raw", Type::UNIT)
     {
-        AddTestCase(new Ipv4RawSocketImplTest, TestCase::QUICK);
+        AddTestCase(new Ipv4RawSocketImplTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-rip-test.cc ns-3.42/src/internet/test/ipv4-rip-test.cc
--- ns-3.41/src/internet/test/ipv4-rip-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-rip-test.cc	2024-05-29 15:29:46.968073100 -0700
@@ -703,13 +703,16 @@
 {
   public:
     Ipv4RipTestSuite()
-        : TestSuite("ipv4-rip", UNIT)
+        : TestSuite("ipv4-rip", Type::UNIT)
     {
-        AddTestCase(new Ipv4RipTest, TestCase::QUICK);
-        AddTestCase(new Ipv4RipCountToInfinityTest, TestCase::QUICK);
-        AddTestCase(new Ipv4RipSplitHorizonStrategyTest(Rip::POISON_REVERSE), TestCase::QUICK);
-        AddTestCase(new Ipv4RipSplitHorizonStrategyTest(Rip::SPLIT_HORIZON), TestCase::QUICK);
-        AddTestCase(new Ipv4RipSplitHorizonStrategyTest(Rip::NO_SPLIT_HORIZON), TestCase::QUICK);
+        AddTestCase(new Ipv4RipTest, TestCase::Duration::QUICK);
+        AddTestCase(new Ipv4RipCountToInfinityTest, TestCase::Duration::QUICK);
+        AddTestCase(new Ipv4RipSplitHorizonStrategyTest(Rip::POISON_REVERSE),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new Ipv4RipSplitHorizonStrategyTest(Rip::SPLIT_HORIZON),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new Ipv4RipSplitHorizonStrategyTest(Rip::NO_SPLIT_HORIZON),
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-static-routing-test-suite.cc ns-3.42/src/internet/test/ipv4-static-routing-test-suite.cc
--- ns-3.41/src/internet/test/ipv4-static-routing-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-static-routing-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -219,9 +219,9 @@
 };
 
 Ipv4StaticRoutingTestSuite::Ipv4StaticRoutingTestSuite()
-    : TestSuite("ipv4-static-routing", UNIT)
+    : TestSuite("ipv4-static-routing", Type::UNIT)
 {
-    AddTestCase(new Ipv4StaticRoutingSlash32TestCase, TestCase::QUICK);
+    AddTestCase(new Ipv4StaticRoutingSlash32TestCase, TestCase::Duration::QUICK);
 }
 
 static Ipv4StaticRoutingTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv4-test.cc ns-3.42/src/internet/test/ipv4-test.cc
--- ns-3.41/src/internet/test/ipv4-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv4-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -129,9 +129,9 @@
 {
   public:
     IPv4L3ProtocolTestSuite()
-        : TestSuite("ipv4-protocol", UNIT)
+        : TestSuite("ipv4-protocol", Type::UNIT)
     {
-        AddTestCase(new Ipv4L3ProtocolTestCase(), TestCase::QUICK);
+        AddTestCase(new Ipv4L3ProtocolTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-address-duplication-test.cc ns-3.42/src/internet/test/ipv6-address-duplication-test.cc
--- ns-3.41/src/internet/test/ipv6-address-duplication-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-address-duplication-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -124,9 +124,9 @@
 {
   public:
     Ipv6DadTestSuite()
-        : TestSuite("ipv6-duplicate-address-detection", UNIT)
+        : TestSuite("ipv6-duplicate-address-detection", Type::UNIT)
     {
-        AddTestCase(new Ipv6DadTest, TestCase::QUICK);
+        AddTestCase(new Ipv6DadTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-address-generator-test-suite.cc ns-3.42/src/internet/test/ipv6-address-generator-test-suite.cc
--- ns-3.41/src/internet/test/ipv6-address-generator-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-address-generator-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -352,11 +352,11 @@
     Ipv6AddressGeneratorTestSuite()
         : TestSuite("ipv6-address-generator")
     {
-        AddTestCase(new NetworkNumber6AllocatorTestCase(), TestCase::QUICK);
-        AddTestCase(new AddressAllocator6TestCase(), TestCase::QUICK);
-        AddTestCase(new NetworkAndAddress6TestCase(), TestCase::QUICK);
-        AddTestCase(new ExampleAddress6GeneratorTestCase(), TestCase::QUICK);
-        AddTestCase(new AddressCollision6TestCase(), TestCase::QUICK);
+        AddTestCase(new NetworkNumber6AllocatorTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new AddressAllocator6TestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new NetworkAndAddress6TestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new ExampleAddress6GeneratorTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new AddressCollision6TestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-address-helper-test-suite.cc ns-3.42/src/internet/test/ipv6-address-helper-test-suite.cc
--- ns-3.41/src/internet/test/ipv6-address-helper-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-address-helper-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -179,9 +179,9 @@
 };
 
 Ipv6AddressHelperTestSuite::Ipv6AddressHelperTestSuite()
-    : TestSuite("ipv6-address-helper", UNIT)
+    : TestSuite("ipv6-address-helper", Type::UNIT)
 {
-    AddTestCase(new IpAddressHelperTestCasev6, TestCase::QUICK);
+    AddTestCase(new IpAddressHelperTestCasev6, TestCase::Duration::QUICK);
 }
 
 static Ipv6AddressHelperTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-dual-stack-test-suite.cc ns-3.42/src/internet/test/ipv6-dual-stack-test-suite.cc
--- ns-3.41/src/internet/test/ipv6-dual-stack-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-dual-stack-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -360,9 +360,9 @@
 {
   public:
     Ipv6DualStackTestSuite()
-        : TestSuite("ipv6-dual-stack", UNIT)
+        : TestSuite("ipv6-dual-stack", Type::UNIT)
     {
-        AddTestCase(new DualStackTestCase(), TestCase::QUICK);
+        AddTestCase(new DualStackTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-extension-header-test-suite.cc ns-3.42/src/internet/test/ipv6-extension-header-test-suite.cc
--- ns-3.41/src/internet/test/ipv6-extension-header-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-extension-header-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -170,7 +170,7 @@
 
     Alignment GetAlignment() const override
     {
-        return (Alignment){4, 0};
+        return Alignment{4, 0};
     }
 };
 
@@ -279,12 +279,12 @@
 {
   public:
     Ipv6ExtensionHeaderTestSuite()
-        : TestSuite("ipv6-extension-header", UNIT)
+        : TestSuite("ipv6-extension-header", Type::UNIT)
     {
-        AddTestCase(new TestEmptyOptionField, TestCase::QUICK);
-        AddTestCase(new TestOptionWithoutAlignment, TestCase::QUICK);
-        AddTestCase(new TestOptionWithAlignment, TestCase::QUICK);
-        AddTestCase(new TestFulfilledAlignment, TestCase::QUICK);
+        AddTestCase(new TestEmptyOptionField, TestCase::Duration::QUICK);
+        AddTestCase(new TestOptionWithoutAlignment, TestCase::Duration::QUICK);
+        AddTestCase(new TestOptionWithAlignment, TestCase::Duration::QUICK);
+        AddTestCase(new TestFulfilledAlignment, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-forwarding-test.cc ns-3.42/src/internet/test/ipv6-forwarding-test.cc
--- ns-3.41/src/internet/test/ipv6-forwarding-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-forwarding-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -218,9 +218,9 @@
 {
   public:
     Ipv6ForwardingTestSuite()
-        : TestSuite("ipv6-forwarding", UNIT)
+        : TestSuite("ipv6-forwarding", Type::UNIT)
     {
-        AddTestCase(new Ipv6ForwardingTest, TestCase::QUICK);
+        AddTestCase(new Ipv6ForwardingTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-fragmentation-test.cc ns-3.42/src/internet/test/ipv6-fragmentation-test.cc
--- ns-3.41/src/internet/test/ipv6-fragmentation-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-fragmentation-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -623,9 +623,9 @@
 {
   public:
     Ipv6FragmentationTestSuite()
-        : TestSuite("ipv6-fragmentation", UNIT)
+        : TestSuite("ipv6-fragmentation", Type::UNIT)
     {
-        AddTestCase(new Ipv6FragmentationTest, TestCase::QUICK);
+        AddTestCase(new Ipv6FragmentationTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-list-routing-test-suite.cc ns-3.42/src/internet/test/ipv6-list-routing-test-suite.cc
--- ns-3.41/src/internet/test/ipv6-list-routing-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-list-routing-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -238,10 +238,10 @@
 {
   public:
     Ipv6ListRoutingTestSuite()
-        : TestSuite("ipv6-list-routing", UNIT)
+        : TestSuite("ipv6-list-routing", Type::UNIT)
     {
-        AddTestCase(new Ipv6ListRoutingPositiveTestCase(), TestCase::QUICK);
-        AddTestCase(new Ipv6ListRoutingNegativeTestCase(), TestCase::QUICK);
+        AddTestCase(new Ipv6ListRoutingPositiveTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new Ipv6ListRoutingNegativeTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-packet-info-tag-test-suite.cc ns-3.42/src/internet/test/ipv6-packet-info-tag-test-suite.cc
--- ns-3.41/src/internet/test/ipv6-packet-info-tag-test-suite.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-packet-info-tag-test-suite.cc	2024-05-29 15:29:46.972073300 -0700
@@ -256,9 +256,9 @@
 };
 
 Ipv6PacketInfoTagTestSuite::Ipv6PacketInfoTagTestSuite()
-    : TestSuite("ipv6-packet-info-tag", UNIT)
+    : TestSuite("ipv6-packet-info-tag", Type::UNIT)
 {
-    AddTestCase(new Ipv6PacketInfoTagTest(), TestCase::QUICK);
+    AddTestCase(new Ipv6PacketInfoTagTest(), TestCase::Duration::QUICK);
 }
 
 static Ipv6PacketInfoTagTestSuite g_packetinfotagTests; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-raw-test.cc ns-3.42/src/internet/test/ipv6-raw-test.cc
--- ns-3.41/src/internet/test/ipv6-raw-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-raw-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -330,9 +330,9 @@
 {
   public:
     Ipv6RawTestSuite()
-        : TestSuite("ipv6-raw", UNIT)
+        : TestSuite("ipv6-raw", Type::UNIT)
     {
-        AddTestCase(new Ipv6RawSocketImplTest, TestCase::QUICK);
+        AddTestCase(new Ipv6RawSocketImplTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-ripng-test.cc ns-3.42/src/internet/test/ipv6-ripng-test.cc
--- ns-3.41/src/internet/test/ipv6-ripng-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-ripng-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -702,14 +702,16 @@
 {
   public:
     Ipv6RipngTestSuite()
-        : TestSuite("ipv6-ripng", UNIT)
+        : TestSuite("ipv6-ripng", Type::UNIT)
     {
-        AddTestCase(new Ipv6RipngTest, TestCase::QUICK);
-        AddTestCase(new Ipv6RipngCountToInfinityTest, TestCase::QUICK);
-        AddTestCase(new Ipv6RipngSplitHorizonStrategyTest(RipNg::POISON_REVERSE), TestCase::QUICK);
-        AddTestCase(new Ipv6RipngSplitHorizonStrategyTest(RipNg::SPLIT_HORIZON), TestCase::QUICK);
+        AddTestCase(new Ipv6RipngTest, TestCase::Duration::QUICK);
+        AddTestCase(new Ipv6RipngCountToInfinityTest, TestCase::Duration::QUICK);
+        AddTestCase(new Ipv6RipngSplitHorizonStrategyTest(RipNg::POISON_REVERSE),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new Ipv6RipngSplitHorizonStrategyTest(RipNg::SPLIT_HORIZON),
+                    TestCase::Duration::QUICK);
         AddTestCase(new Ipv6RipngSplitHorizonStrategyTest(RipNg::NO_SPLIT_HORIZON),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/ipv6-test.cc ns-3.42/src/internet/test/ipv6-test.cc
--- ns-3.41/src/internet/test/ipv6-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/ipv6-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -186,9 +186,9 @@
 {
   public:
     IPv6L3ProtocolTestSuite()
-        : TestSuite("ipv6-protocol", UNIT)
+        : TestSuite("ipv6-protocol", Type::UNIT)
     {
-        AddTestCase(new Ipv6L3ProtocolTestCase(), TestCase::QUICK);
+        AddTestCase(new Ipv6L3ProtocolTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/neighbor-cache-test.cc ns-3.42/src/internet/test/neighbor-cache-test.cc
--- ns-3.41/src/internet/test/neighbor-cache-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/neighbor-cache-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -1230,15 +1230,15 @@
 {
   public:
     NeighborCacheTestSuite()
-        : TestSuite("neighbor-cache", UNIT)
+        : TestSuite("neighbor-cache", Type::UNIT)
     {
-        AddTestCase(new DynamicNeighborCacheTest, TestCase::QUICK);
-        AddTestCase(new ChannelTest, TestCase::QUICK);
-        AddTestCase(new NetDeviceContainerTest, TestCase::QUICK);
-        AddTestCase(new InterfaceContainerTest, TestCase::QUICK);
-        AddTestCase(new FlushTest, TestCase::QUICK);
-        AddTestCase(new DuplicateTest, TestCase::QUICK);
-        AddTestCase(new DynamicPartialTest, TestCase::QUICK);
+        AddTestCase(new DynamicNeighborCacheTest, TestCase::Duration::QUICK);
+        AddTestCase(new ChannelTest, TestCase::Duration::QUICK);
+        AddTestCase(new NetDeviceContainerTest, TestCase::Duration::QUICK);
+        AddTestCase(new InterfaceContainerTest, TestCase::Duration::QUICK);
+        AddTestCase(new FlushTest, TestCase::Duration::QUICK);
+        AddTestCase(new DuplicateTest, TestCase::Duration::QUICK);
+        AddTestCase(new DynamicPartialTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/rtt-test.cc ns-3.42/src/internet/test/rtt-test.cc
--- ns-3.41/src/internet/test/rtt-test.cc	2024-02-09 14:44:07.945790300 -0800
+++ ns-3.42/src/internet/test/rtt-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -187,9 +187,9 @@
 {
   public:
     RttEstimatorTestSuite()
-        : TestSuite("rtt-estimator", UNIT)
+        : TestSuite("rtt-estimator", Type::UNIT)
     {
-        AddTestCase(new RttEstimatorTestCase, TestCase::QUICK);
+        AddTestCase(new RttEstimatorTestCase, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-advertised-window-test.cc ns-3.42/src/internet/test/tcp-advertised-window-test.cc
--- ns-3.41/src/internet/test/tcp-advertised-window-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-advertised-window-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -28,7 +28,7 @@
 NS_LOG_COMPONENT_DEFINE("TcpAdvertisedWindowTestSuite");
 
 /**
- * \ingroup internet-tests
+ * \ingroup internet-test
  * \ingroup tests
  * \brief Socket that wraps every call to AdvertisedWindowSize ().
  */
@@ -206,8 +206,8 @@
 NS_OBJECT_ENSURE_REGISTERED(TcpSocketAdvertisedWindowProxy);
 
 /**
- * \ingroup internet-tests
- * \ingroup test
+ * \ingroup internet-test
+ * \ingroup tests
  *
  * \brief An error model that randomly drops a given rátio of TCP segments.
  */
@@ -260,8 +260,8 @@
 }
 
 /**
- * \ingroup internet-tests
- * \ingroup test
+ * \ingroup internet-test
+ * \ingroup tests
  * \brief Test the new formula for calculating TCP's advertised window size.
  *
  * In TcpSocketBase, the advertised window is now calculated as
@@ -363,8 +363,8 @@
 //-----------------------------------------------------------------------------
 
 /**
- * \ingroup internet-tests
- * \ingroup test
+ * \ingroup internet-test
+ * \ingroup tests
  * \brief Test the TCP's advertised window size when there is a loss of specific packets.
  */
 class TcpAdvWindowOnLossTest : public TcpGeneralTest
@@ -464,8 +464,8 @@
 //-----------------------------------------------------------------------------
 
 /**
- * \ingroup internet-tests
- * \ingroup test
+ * \ingroup internet-test
+ * \ingroup tests
  *
  * \brief Test Suite for TCP adv window
  */
@@ -473,39 +473,39 @@
 {
   public:
     TcpAdvertisedWindowTestSuite()
-        : TestSuite("tcp-advertised-window-test", UNIT)
+        : TestSuite("tcp-advertised-window-test", Type::UNIT)
     {
         AddTestCase(new TcpAdvertisedWindowTest("TCP advertised window size, small seg + no loss",
                                                 500,
                                                 100,
                                                 0.0),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpAdvertisedWindowTest("TCP advertised window size, small seg + loss",
                                                 500,
                                                 100,
                                                 0.1),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpAdvertisedWindowTest("TCP advertised window size, large seg + no loss",
                                                 1000,
                                                 100,
                                                 0.0),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpAdvertisedWindowTest("TCP advertised window size, large seg + small loss",
                                         1000,
                                         100,
                                         0.1),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new TcpAdvertisedWindowTest("TCP advertised window size, large seg + big loss",
                                                 1000,
                                                 100,
                                                 0.3),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpAdvertisedWindowTest("TCP advertised window size, complete loss",
                                                 1000,
                                                 100,
                                                 1.0),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         std::vector<uint32_t> toDrop;
         toDrop.push_back(8001);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-bbr-test.cc ns-3.42/src/internet/test/tcp-bbr-test.cc
--- ns-3.41/src/internet/test/tcp-bbr-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-bbr-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -192,40 +192,40 @@
      * \brief constructor
      */
     TcpBbrTestSuite()
-        : TestSuite("tcp-bbr-test", UNIT)
+        : TestSuite("tcp-bbr-test", Type::UNIT)
     {
         AddTestCase(new TcpBbrPacingEnableTest(true, "BBR must keep pacing feature on"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(new TcpBbrPacingEnableTest(false, "BBR must turn on pacing feature"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpBbrCheckGainValuesTest(
                 TcpBbr::BBR_STARTUP,
                 4,
                 "BBR should enter to STARTUP phase and set cwnd and pacing gain accordingly"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(new TcpBbrCheckGainValuesTest(
                         TcpBbr::BBR_DRAIN,
                         4,
                         "BBR should enter to DRAIN phase and set cwnd and pacing gain accordingly"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpBbrCheckGainValuesTest(
                 TcpBbr::BBR_PROBE_BW,
                 4,
                 "BBR should enter to BBR_PROBE_BW phase and set cwnd and pacing gain accordingly"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpBbrCheckGainValuesTest(
                 TcpBbr::BBR_PROBE_RTT,
                 4,
                 "BBR should enter to BBR_PROBE_RTT phase and set cwnd and pacing gain accordingly"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-bic-test.cc ns-3.42/src/internet/test/tcp-bic-test.cc
--- ns-3.41/src/internet/test/tcp-bic-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-bic-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -310,7 +310,7 @@
 {
   public:
     TcpBicTestSuite()
-        : TestSuite("tcp-bic-test", UNIT)
+        : TestSuite("tcp-bic-test", Type::UNIT)
     {
         AddTestCase(
             new TcpBicIncrementTest(10 * 536,
@@ -319,7 +319,7 @@
                                     11,
                                     0,
                                     "Bic increment test: under lowCwnd & enough ACKs received"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new TcpBicIncrementTest(
                         10 * 536,
                         536,
@@ -327,7 +327,7 @@
                         8,
                         0,
                         "Bic increment test: under lowCwnd but not enough ACKs received"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpBicIncrementTest(
                         18 * 1446,
                         1446,
@@ -335,7 +335,7 @@
                         5,
                         90,
                         "Bic increment test: linear increase when distance exceeds S_max"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpBicIncrementTest(18 * 1446,
                                     1446,
@@ -343,21 +343,21 @@
                                     24,
                                     20,
                                     "Bic increment test: binary search increase with smooth part"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new TcpBicIncrementTest(19 * 1,
                                             1,
                                             17 * 1,
                                             2,
                                             83,
                                             "Bic increment test: binary search increase"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpBicIncrementTest(15 * 536,
                                             536,
                                             9 * 536,
                                             19,
                                             13,
                                             "Bic increment test: slow start AMD linear increase"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpBicIncrementTest(22 * 1000,
                                     1000,
@@ -365,15 +365,15 @@
                                     9,
                                     16,
                                     "Bic increment test: slow start but not enough ACKs received"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new TcpBicIncrementTest(
                         65 * 1000,
                         1000,
                         9 * 1000,
                         2,
                         16,
-                        "Bic increment test: linear incrase but not enough ACKs received"),
-                    TestCase::QUICK);
+                        "Bic increment test: linear increase but not enough ACKs received"),
+                    TestCase::Duration::QUICK);
 
         AddTestCase(new TcpBicDecrementTest(
                         5 * 1446,
@@ -381,14 +381,14 @@
                         true,
                         10,
                         "Bic decrement test: fast convergence & cwnd less than lowWindow"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpBicDecrementTest(
                         5 * 1446,
                         1446,
                         false,
                         10,
                         "Bic decrement test: not in fast convergence & cwnd less than lowWindow"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpBicDecrementTest(
                 15 * 1446,
@@ -396,7 +396,7 @@
                 false,
                 10,
                 "Bic decrement test: not in fast convergence & cwnd greater than lowWindow"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-bytes-in-flight-test.cc ns-3.42/src/internet/test/tcp-bytes-in-flight-test.cc
--- ns-3.41/src/internet/test/tcp-bytes-in-flight-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-bytes-in-flight-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -289,24 +289,24 @@
 {
   public:
     TcpBytesInFlightTestSuite()
-        : TestSuite("tcp-bytes-in-flight-test", UNIT)
+        : TestSuite("tcp-bytes-in-flight-test", Type::UNIT)
     {
         std::vector<uint32_t> toDrop;
         AddTestCase(new TcpBytesInFlightTest("BytesInFlight value, no drop", toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         toDrop.push_back(4001);
         AddTestCase(new TcpBytesInFlightTest("BytesInFlight value, one drop", toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         toDrop.push_back(4001);
         AddTestCase(
             new TcpBytesInFlightTest("BytesInFlight value, two drop of same segment", toDrop),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         toDrop.pop_back();
         toDrop.push_back(4501);
         AddTestCase(
             new TcpBytesInFlightTest("BytesInFlight value, two drop of consecutive segments",
                                      toDrop),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-classic-recovery-test.cc ns-3.42/src/internet/test/tcp-classic-recovery-test.cc
--- ns-3.41/src/internet/test/tcp-classic-recovery-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-classic-recovery-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -126,44 +126,44 @@
 {
   public:
     ClassicRecoveryTestSuite()
-        : TestSuite("tcp-classic-recovery-test", UNIT)
+        : TestSuite("tcp-classic-recovery-test", Type::UNIT)
     {
         AddTestCase(new ClassicRecoveryTest(3000,
                                             500,
                                             2500,
                                             3,
                                             "Classic recovery test with 500 bytes segmentSize"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new ClassicRecoveryTest(3000,
                                             1000,
                                             2500,
                                             3,
                                             "Classic recovery test with 1000 bytes segmentSize"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new ClassicRecoveryTest(3000,
                                             500,
                                             2500,
                                             4,
                                             "Classic recovery test with 4 DupAck threshold"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new ClassicRecoveryTest(3000,
                                             500,
                                             1000,
                                             3,
                                             "Classic recovery test with 1000 bytes ssThresh"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new ClassicRecoveryTest(2500,
                                             500,
                                             2500,
                                             3,
                                             "Classic recovery test with same cWnd and ssThresh"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new ClassicRecoveryTest(1000,
                                             500,
                                             2500,
                                             3,
                                             "Classic recovery test with cWnd lesser than ssThresh"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-close-test.cc ns-3.42/src/internet/test/tcp-close-test.cc
--- ns-3.41/src/internet/test/tcp-close-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-close-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -159,10 +159,10 @@
 {
   public:
     TcpTcpCloseTestSuite()
-        : TestSuite("tcp-close", UNIT)
+        : TestSuite("tcp-close", Type::UNIT)
     {
-        AddTestCase(new TcpCloseWithLossTestCase(true), TestCase::QUICK);
-        AddTestCase(new TcpCloseWithLossTestCase(false), TestCase::QUICK);
+        AddTestCase(new TcpCloseWithLossTestCase(true), TestCase::Duration::QUICK);
+        AddTestCase(new TcpCloseWithLossTestCase(false), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-cong-avoid-test.cc ns-3.42/src/internet/test/tcp-cong-avoid-test.cc
--- ns-3.41/src/internet/test/tcp-cong-avoid-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-cong-avoid-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -132,7 +132,7 @@
         return;
     }
 
-    if (!m_event.IsRunning())
+    if (!m_event.IsPending())
     {
         m_event = Simulator::Schedule(Seconds(1.0), &TcpNewRenoCongAvoidNormalTest::Check, this);
     }
@@ -187,7 +187,7 @@
 {
   public:
     TcpRenoCongAvoidTestSuite()
-        : TestSuite("tcp-cong-avoid-test", UNIT)
+        : TestSuite("tcp-cong-avoid-test", Type::UNIT)
     {
         std::list<TypeId> types = {
             TcpNewReno::GetTypeId(),
@@ -205,14 +205,14 @@
                                                               t,
                                                               "cong avoid MSS=500, pkt_size=500," +
                                                                   typeName),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 AddTestCase(new TcpNewRenoCongAvoidNormalTest(500,
                                                               1000,
                                                               i,
                                                               t,
                                                               "cong avoid MSS=500, pkt_size=1000," +
                                                                   typeName),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
             }
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-datasentcb-test.cc ns-3.42/src/internet/test/tcp-datasentcb-test.cc
--- ns-3.41/src/internet/test/tcp-datasentcb-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-datasentcb-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -169,18 +169,18 @@
 {
   public:
     TcpDataSentCbTestSuite()
-        : TestSuite("tcp-datasentcb", UNIT)
+        : TestSuite("tcp-datasentcb", Type::UNIT)
     {
         AddTestCase(new TcpDataSentCbTestCase("Check the data sent callback", 500, 10),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDataSentCbTestCase("Check the data sent callback", 100, 100),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDataSentCbTestCase("Check the data sent callback", 1000, 50),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDataSentCbTestCase("Check the data sent callback", 855, 18),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDataSentCbTestCase("Check the data sent callback", 1243, 59),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-dctcp-test.cc ns-3.42/src/internet/test/tcp-dctcp-test.cc
--- ns-3.41/src/internet/test/tcp-dctcp-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-dctcp-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -659,7 +659,7 @@
 {
   public:
     TcpDctcpTestSuite()
-        : TestSuite("tcp-dctcp-test", UNIT)
+        : TestSuite("tcp-dctcp-test", Type::UNIT)
     {
         AddTestCase(new TcpDctcpToLinuxReno(2 * 1446,
                                             1446,
@@ -669,20 +669,20 @@
                                             SequenceNumber32(3216),
                                             MilliSeconds(100),
                                             "DCTCP falls to New Reno for slowstart"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDctcpCodePointsTest(1,
                                                "ECT Test : Check if ECT is set on Syn, Syn+Ack, "
                                                "Ack and Data packets for DCTCP packets"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDctcpCodePointsTest(
                         2,
                         "ECT Test : Check if ECT is not set on Syn, Syn+Ack and Ack but set on "
                         "Data packets for non-DCTCP but ECN enabled traffic"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpDctcpCodePointsTest(3,
                                                "ECE Functionality Test: ECE should only be sent by "
                                                "receiver when it receives CE flags"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-ecn-test.cc ns-3.42/src/internet/test/tcp-ecn-test.cc
--- ns-3.41/src/internet/test/tcp-ecn-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-ecn-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -195,11 +195,8 @@
     if (GetIpTos())
     {
         SocketIpTosTag ipTosTag;
-        if (m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3))
-        {
-            ipTosTag.SetTos(MarkEcnCe(GetIpTos()));
-        }
-        else if (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5))
+        if ((m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3)) ||
+            (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5)))
         {
             ipTosTag.SetTos(MarkEcnCe(GetIpTos()));
         }
@@ -219,11 +216,8 @@
     else
     {
         SocketIpTosTag ipTosTag;
-        if (m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3))
-        {
-            ipTosTag.SetTos(MarkEcnCe(GetIpTos()));
-        }
-        else if (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5))
+        if ((m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3)) ||
+            (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5)))
         {
             ipTosTag.SetTos(MarkEcnCe(GetIpTos()));
         }
@@ -240,11 +234,8 @@
     if (IsManualIpv6Tclass())
     {
         SocketIpv6TclassTag ipTclassTag;
-        if (m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3))
-        {
-            ipTclassTag.SetTclass(MarkEcnCe(GetIpv6Tclass()));
-        }
-        else if (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5))
+        if ((m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3)) ||
+            (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5)))
         {
             ipTclassTag.SetTclass(MarkEcnCe(GetIpv6Tclass()));
         }
@@ -264,11 +255,8 @@
     else
     {
         SocketIpv6TclassTag ipTclassTag;
-        if (m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3))
-        {
-            ipTclassTag.SetTclass(MarkEcnCe(GetIpv6Tclass()));
-        }
-        else if (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5))
+        if ((m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 3)) ||
+            (m_testcase == 6 && (m_dataPacketSent == 4 || m_dataPacketSent == 5)))
         {
             ipTclassTag.SetTclass(MarkEcnCe(GetIpv6Tclass()));
         }
@@ -585,33 +573,33 @@
 {
   public:
     TcpEcnTestSuite()
-        : TestSuite("tcp-ecn-test", UNIT)
+        : TestSuite("tcp-ecn-test", Type::UNIT)
     {
         AddTestCase(new TcpEcnTest(
                         1,
                         "ECN Negotiation Test : ECN incapable sender and ECN incapable receiver"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpEcnTest(2,
                            "ECN Negotiation Test : ECN capable sender and ECN incapable receiver"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new TcpEcnTest(3,
                            "ECN Negotiation Test : ECN incapable sender and ECN capable receiver"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new TcpEcnTest(4, "ECN Negotiation Test : ECN capable sender and ECN capable receiver"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new TcpEcnTest(
                 5,
                 "ECE and CWR Functionality Test: ECN capable sender and ECN capable receiver"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new TcpEcnTest(
                 6,
                 "Congestion Window Reduction Test :ECN capable sender and ECN capable receiver"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-endpoint-bug2211.cc ns-3.42/src/internet/test/tcp-endpoint-bug2211.cc
--- ns-3.41/src/internet/test/tcp-endpoint-bug2211.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-endpoint-bug2211.cc	2024-05-29 15:29:46.972073300 -0700
@@ -157,10 +157,12 @@
 {
   public:
     TcpEndpointBug2211TestSuite()
-        : TestSuite("tcp-endpoint-bug2211-test", UNIT)
+        : TestSuite("tcp-endpoint-bug2211-test", Type::UNIT)
     {
-        AddTestCase(new TcpEndPointBug2211Test("Bug 2211 testcase IPv4", false), TestCase::QUICK);
-        AddTestCase(new TcpEndPointBug2211Test("Bug 2211 testcase IPv6", true), TestCase::QUICK);
+        AddTestCase(new TcpEndPointBug2211Test("Bug 2211 testcase IPv4", false),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcpEndPointBug2211Test("Bug 2211 testcase IPv6", true),
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-fast-retr-test.cc ns-3.42/src/internet/test/tcp-fast-retr-test.cc
--- ns-3.41/src/internet/test/tcp-fast-retr-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-fast-retr-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -208,14 +208,10 @@
             }
         }
 
-        if (m_sndNextExpSeq.GetValue() == 0)
+        // SYN or Pure ACK in three-way handshake, then we expect data
+        if ((m_sndNextExpSeq.GetValue() == 0) ||
+            (m_sndNextExpSeq.GetValue() == 1 && p->GetSize() == 32))
         {
-            // SYN
-            m_sndNextExpSeq = SequenceNumber32(1);
-        }
-        else if (m_sndNextExpSeq.GetValue() == 1 && p->GetSize() == 32)
-        {
-            // Pure ACK in three-way handshake, then we expect data
             m_sndNextExpSeq = SequenceNumber32(1);
         }
         else
@@ -437,7 +433,7 @@
 {
   public:
     TcpFastRetrTestSuite()
-        : TestSuite("tcp-fast-retr-test", UNIT)
+        : TestSuite("tcp-fast-retr-test", Type::UNIT)
     {
         std::list<TypeId> types;
         types.insert(types.begin(), TcpWestwoodPlus::GetTypeId());
@@ -446,7 +442,7 @@
         for (auto it = types.begin(); it != types.end(); ++it)
         {
             AddTestCase(new TcpFastRetrTest((*it), 5001, "Fast Retransmit testing"),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
         }
     }
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-header-test.cc ns-3.42/src/internet/test/tcp-header-test.cc
--- ns-3.41/src/internet/test/tcp-header-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-header-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -206,12 +206,12 @@
 {
     TcpHeader source;
     TcpHeader destination;
-    TcpOptionNOP temp;
+    auto temp = CreateObject<TcpOptionNOP>();
     Buffer buffer;
     buffer.AddAtStart(40);
 
     Buffer::Iterator i = buffer.Begin();
-    source.AppendOption(&temp);
+    source.AppendOption(temp);
 
     source.Serialize(i);
 
@@ -460,12 +460,13 @@
 {
   public:
     TcpHeaderTestSuite()
-        : TestSuite("tcp-header", UNIT)
+        : TestSuite("tcp-header", Type::UNIT)
     {
-        AddTestCase(new TcpHeaderGetSetTestCase("GetSet test cases"), TestCase::QUICK);
+        AddTestCase(new TcpHeaderGetSetTestCase("GetSet test cases"), TestCase::Duration::QUICK);
         AddTestCase(new TcpHeaderWithRFC793OptionTestCase("Test for options in RFC 793"),
-                    TestCase::QUICK);
-        AddTestCase(new TcpHeaderFlagsToString("Test flags to string function"), TestCase::QUICK);
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcpHeaderFlagsToString("Test flags to string function"),
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-highspeed-test.cc ns-3.42/src/internet/test/tcp-highspeed-test.cc
--- ns-3.41/src/internet/test/tcp-highspeed-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-highspeed-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -183,7 +183,7 @@
 {
   public:
     TcpHighSpeedTestSuite()
-        : TestSuite("tcp-highspeed-test", UNIT)
+        : TestSuite("tcp-highspeed-test", Type::UNIT)
     {
         std::stringstream ss;
 
@@ -194,32 +194,32 @@
                 new TcpHighSpeedIncrementTest(highSpeedImportantValues[i].cwnd,
                                               1,
                                               "Highspeed increment test on cWnd " + ss.str()),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpHighSpeedIncrementTest(highSpeedImportantValues[i].cwnd * 536,
                                               536,
                                               "Highspeed increment test on cWnd " + ss.str()),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpHighSpeedIncrementTest(highSpeedImportantValues[i].cwnd * 1446,
                                               1446,
                                               "Highspeed increment test on cWnd " + ss.str()),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpHighSpeedDecrementTest(highSpeedImportantValues[i].cwnd,
                                               1,
                                               "Highspeed Decrement test on cWnd " + ss.str()),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpHighSpeedDecrementTest(highSpeedImportantValues[i].cwnd * 536,
                                               536,
                                               "Highspeed Decrement test on cWnd " + ss.str()),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpHighSpeedDecrementTest(highSpeedImportantValues[i].cwnd * 1446,
                                               1446,
                                               "Highspeed Decrement test on cWnd " + ss.str()),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             ss.flush();
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-htcp-test.cc ns-3.42/src/internet/test/tcp-htcp-test.cc
--- ns-3.41/src/internet/test/tcp-htcp-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-htcp-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -165,7 +165,7 @@
 {
   public:
     TcpHtcpTestSuite()
-        : TestSuite("tcp-htcp-test", UNIT)
+        : TestSuite("tcp-htcp-test", Type::UNIT)
     {
         AddTestCase(new TcpHtcpIncrementTest(38 * 536,
                                              536,
@@ -175,7 +175,7 @@
                                              ns3::MilliSeconds(1000),
                                              20383,
                                              "TcpHtcp increment test on cWnd "),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHtcpIncrementTest(38,
                                              1,
                                              100,
@@ -184,7 +184,7 @@
                                              ns3::MilliSeconds(1100),
                                              40,
                                              "TcpHtcp increment test on cWnd "),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHtcpIncrementTest(53 * 1446,
                                              1446,
                                              50,
@@ -193,7 +193,7 @@
                                              ns3::MilliSeconds(1500),
                                              76671,
                                              "TcpHtcp increment test on cWnd "),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-hybla-test.cc ns-3.42/src/internet/test/tcp-hybla-test.cc
--- ns-3.41/src/internet/test/tcp-hybla-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-hybla-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -155,32 +155,32 @@
 {
   public:
     TcpHyblaTestSuite()
-        : TestSuite("tcp-hybla-test", UNIT)
+        : TestSuite("tcp-hybla-test", Type::UNIT)
     {
         AddTestCase(new TcpHyblaIncrementTest(1000,
                                               0xFFFFFFFF,
                                               500,
                                               MilliSeconds(55),
                                               "Rho=1.1, slow start"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHyblaIncrementTest(1000,
                                               0xFFFFFFFF,
                                               500,
                                               MilliSeconds(100),
                                               "Rho=2, slow start"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHyblaIncrementTest(1000,
                                               0xFFFFFFFF,
                                               500,
                                               MilliSeconds(750),
                                               "Rho=30, slow start"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHyblaIncrementTest(1000, 500, 500, Seconds(0.55), "Rho=1.1, cong avoid"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHyblaIncrementTest(1000, 500, 500, Seconds(0.1), "Rho=2, cong avoid"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpHyblaIncrementTest(1000, 500, 500, Seconds(0.75), "Rho=30, cong avoid"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-illinois-test.cc ns-3.42/src/internet/test/tcp-illinois-test.cc
--- ns-3.41/src/internet/test/tcp-illinois-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-illinois-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -352,7 +352,7 @@
 {
   public:
     TcpIllinoisTestSuite()
-        : TestSuite("tcp-illinois-test", UNIT)
+        : TestSuite("tcp-illinois-test", Type::UNIT)
     {
         AddTestCase(new TcpIllinoisTest(38 * 1446,
                                         40 * 1446,
@@ -363,7 +363,7 @@
                                         SequenceNumber32(2893),
                                         SequenceNumber32(5785),
                                         "Illinois test on cWnd and ssThresh when in slow start"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpIllinoisTest(
                         60 * 346,
                         40 * 346,
@@ -374,7 +374,7 @@
                         SequenceNumber32(2893),
                         SequenceNumber32(5785),
                         "Illinois test on cWnd and ssThresh when avg queueing delay is at minimum"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpIllinoisTest(
                         38 * 1446,
                         40 * 1446,
@@ -385,7 +385,7 @@
                         SequenceNumber32(2893),
                         SequenceNumber32(5785),
                         "Illinois test on cWnd and ssThresh when avg queueing delay is at maximum"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpIllinoisTest(40 * 1446,
                                         38 * 1446,
                                         1446,
@@ -396,7 +396,7 @@
                                         SequenceNumber32(5785),
                                         "Illinois test on cWnd and ssThresh when avg queueing "
                                         "delay is in between its min & max"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-ledbat-test.cc ns-3.42/src/internet/test/tcp-ledbat-test.cc
--- ns-3.41/src/internet/test/tcp-ledbat-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-ledbat-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -343,7 +343,7 @@
 {
   public:
     TcpLedbatTestSuite()
-        : TestSuite("tcp-ledbat-test", UNIT)
+        : TestSuite("tcp-ledbat-test", Type::UNIT)
     {
         AddTestCase(new TcpLedbatToNewReno(2 * 1446,
                                            1446,
@@ -353,7 +353,7 @@
                                            SequenceNumber32(3216),
                                            MilliSeconds(100),
                                            "LEDBAT falls to New Reno for slowstart"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpLedbatToNewReno(4 * 1446,
                                            1446,
                                            2 * 1446,
@@ -362,7 +362,7 @@
                                            SequenceNumber32(3216),
                                            MilliSeconds(100),
                                            "LEDBAT falls to New Reno if timestamps are not found"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpLedbatIncrementTest(2 * 1446,
                                                1446,
                                                4 * 1446,
@@ -371,7 +371,7 @@
                                                SequenceNumber32(3216),
                                                MilliSeconds(100),
                                                "LEDBAT increment test"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpLedbatDecrementTest(2 * 1446,
                                                1446,
                                                4 * 1446,
@@ -380,7 +380,7 @@
                                                SequenceNumber32(3216),
                                                MilliSeconds(100),
                                                "LEDBAT decrement test"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-linux-reno-test.cc ns-3.42/src/internet/test/tcp-linux-reno-test.cc
--- ns-3.41/src/internet/test/tcp-linux-reno-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-linux-reno-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -377,7 +377,7 @@
 {
   public:
     TcpLinuxRenoTestSuite()
-        : TestSuite("tcp-linux-reno-test", UNIT)
+        : TestSuite("tcp-linux-reno-test", Type::UNIT)
     {
         TypeId cong_control_type = TcpLinuxReno::GetTypeId();
         // Test the behavior of Slow Start phase with small segment size
@@ -413,7 +413,7 @@
                                    cong_control_type,
                                    "Slow Start MSS = 524, socket send size = 524, delack = 1 " +
                                        cong_control_type.GetName()),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         // Next, enabling delayed acks should not have an effect on the final
         // cWnd achieved
@@ -427,7 +427,7 @@
                                    cong_control_type,
                                    "Slow Start MSS = 524, socket send size = 524, delack = 2 " +
                                        cong_control_type.GetName()),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         // Test the behavior of Slow Start phase with standard segment size
         // (1500 bytes) and delayed acknowledgement of 1 and 2 segments
@@ -443,7 +443,7 @@
                                    cong_control_type,
                                    "Slow Start MSS = 1500, socket send size = 524, delack = 1 " +
                                        cong_control_type.GetName()),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         // Enable delayed acks; we still expect m_cWnd to end up at 9 segments
         AddTestCase(
@@ -456,7 +456,7 @@
                                    cong_control_type,
                                    "Slow Start MSS = 1500, socket send size = 524, delack = 2 " +
                                        cong_control_type.GetName()),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         // Test the behavior of Congestion Avoidance phase with small segment size
         // (524 bytes) and delayed acknowledgement of 1 and 2.  One important thing
@@ -497,7 +497,7 @@
                         cong_control_type,
                         "Congestion Avoidance MSS = 524, socket send size = 524, delack = 1 " +
                             cong_control_type.GetName()),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // Repeat with delayed acks enabled:  should result in same final cWnd
         // Expected data pattern starting at simulation time 10:
@@ -527,7 +527,7 @@
                         cong_control_type,
                         "Congestion Avoidance MSS = 524, socket send size = 524, delack = 2 " +
                             cong_control_type.GetName()),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // Test the behavior of Congestion Avoidance phase with standard segment size (i.e 1500
         // bytes) and delayed acknowledgement of 1 and 2 Test the behavior of Congestion Avoidance
@@ -545,7 +545,7 @@
                         cong_control_type,
                         "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 1 " +
                             cong_control_type.GetName()),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(new TcpLinuxRenoCongAvoidTest(
                         1500,     // segment size
@@ -558,7 +558,7 @@
                         cong_control_type,
                         "Congestion Avoidance MSS = 1500, socket send size = 1500, delack = 2 " +
                             cong_control_type.GetName()),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-loss-test.cc ns-3.42/src/internet/test/tcp-loss-test.cc
--- ns-3.41/src/internet/test/tcp-loss-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-loss-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -182,7 +182,7 @@
 {
   public:
     TcpLossTestSuite()
-        : TestSuite("tcp-loss-test", UNIT)
+        : TestSuite("tcp-loss-test", Type::UNIT)
     {
         // For large transfer tests, the three sequence numbers passed in
         // are the segment (i.e. not byte) number that should be dropped first,
@@ -192,13 +192,13 @@
         // the TCP logic should correctly pass this case (no sequence wrapping).
         AddTestCase(
             new TcpLargeTransferLossTest(1000, 2000, 2500, "large-transfer-loss-without-wrap"),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         // If we force a loss at packet 1000 and then much later at 3294967, the
         // second sequence number will evaluate to less than 1000 considering
         // the sequence space wrap, so check this case also.
         AddTestCase(
             new TcpLargeTransferLossTest(1000, 3294967, 3295100, "large-transfer-loss-with-wrap"),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-lp-test.cc ns-3.42/src/internet/test/tcp-lp-test.cc
--- ns-3.41/src/internet/test/tcp-lp-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-lp-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -262,7 +262,7 @@
 {
   public:
     TcpLpTestSuite()
-        : TestSuite("tcp-lp-test", UNIT)
+        : TestSuite("tcp-lp-test", Type::UNIT)
     {
         AddTestCase(new TcpLpToNewReno(4 * 1446,
                                        1446,
@@ -270,7 +270,7 @@
                                        2 * 1446,
                                        MilliSeconds(100),
                                        "LP falls to New Reno if the cwd is within threshold"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(new TcpLpInferenceTest1(
                         2 * 1446,
@@ -278,7 +278,7 @@
                         2,
                         MilliSeconds(100),
                         "LP enters Inference phase when cwd exceeds threshold for the first time"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(new TcpLpInferenceTest2(
                         2 * 1446,
@@ -286,7 +286,7 @@
                         2,
                         MilliSeconds(100),
                         "LP reduces cWnd to 1 if cwd exceeds threshold in inference phase"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-option-test.cc ns-3.42/src/internet/test/tcp-option-test.cc
--- ns-3.41/src/internet/test/tcp-option-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-option-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -203,14 +203,15 @@
 {
   public:
     TcpOptionTestSuite()
-        : TestSuite("tcp-option", UNIT)
+        : TestSuite("tcp-option", Type::UNIT)
     {
         for (uint8_t i = 0; i < 15; ++i)
         {
-            AddTestCase(new TcpOptionWSTestCase("Testing window scale value", i), TestCase::QUICK);
+            AddTestCase(new TcpOptionWSTestCase("Testing window scale value", i),
+                        TestCase::Duration::QUICK);
         }
         AddTestCase(new TcpOptionTSTestCase("Testing serialization of random values for timestamp"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-pacing-test.cc ns-3.42/src/internet/test/tcp-pacing-test.cc
--- ns-3.41/src/internet/test/tcp-pacing-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-pacing-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -372,7 +372,7 @@
 {
   public:
     TcpPacingTestSuite()
-        : TestSuite("tcp-pacing-test", UNIT)
+        : TestSuite("tcp-pacing-test", Type::UNIT)
     {
         uint16_t pacingSsRatio = 200;
         uint16_t pacingCaRatio = 120;
@@ -396,7 +396,7 @@
                                       delAckMaxCount,
                                       tid,
                                       description),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         paceInitialWindow = true;
         description = std::string("Pacing case 2: Slow start only, initial pacing");
@@ -410,7 +410,7 @@
                                       delAckMaxCount,
                                       tid,
                                       description),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // set ssThresh to some smaller value to check that pacing
         // slows down in second half of slow start, then transitions to CA
@@ -429,7 +429,7 @@
                                       delAckMaxCount,
                                       tid,
                                       description),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // Repeat tests, but with more typical delAckMaxCount == 2
         delAckMaxCount = 2;
@@ -448,7 +448,7 @@
                                       delAckMaxCount,
                                       tid,
                                       description),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         paceInitialWindow = true;
         description = std::string("Pacing case 5: Slow start only, initial pacing, delayed ACKs");
@@ -462,7 +462,7 @@
                                       delAckMaxCount,
                                       tid,
                                       description),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         description = std::string("Pacing case 6: Slow start, followed by transition to Congestion "
                                   "avoidance, no initial pacing, delayed ACKs");
@@ -479,7 +479,7 @@
                                       delAckMaxCount,
                                       tid,
                                       description),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-pkts-acked-test.cc ns-3.42/src/internet/test/tcp-pkts-acked-test.cc
--- ns-3.41/src/internet/test/tcp-pkts-acked-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-pkts-acked-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -178,10 +178,10 @@
 {
   public:
     TcpPktsAckedTestSuite()
-        : TestSuite("tcp-pkts-acked-test", UNIT)
+        : TestSuite("tcp-pkts-acked-test", Type::UNIT)
     {
         AddTestCase(new TcpPktsAckedOpenTest("PktsAcked check while in OPEN state"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         // Add DISORDER, RECOVERY and LOSS state check
     }
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-prr-recovery-test.cc ns-3.42/src/internet/test/tcp-prr-recovery-test.cc
--- ns-3.41/src/internet/test/tcp-prr-recovery-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-prr-recovery-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -152,7 +152,7 @@
 {
   public:
     PrrRecoveryTestSuite()
-        : TestSuite("tcp-prr-recovery-test", UNIT)
+        : TestSuite("tcp-prr-recovery-test", Type::UNIT)
     {
         AddTestCase(new PrrRecoveryTest(
                         3000,
@@ -164,7 +164,7 @@
                         1000,
                         "SSRB",
                         "Prr test on cWnd when bytesInFlight is greater than ssThresh with SSRB"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new PrrRecoveryTest(
                         1000,
                         500,
@@ -175,7 +175,7 @@
                         1000,
                         "SSRB",
                         "Prr test on cWnd when bytesInFlight is lower than ssThresh with SSRB"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new PrrRecoveryTest(
                         3000,
                         500,
@@ -186,7 +186,7 @@
                         1000,
                         "CRB",
                         "Prr test on cWnd when bytesInFlight is greater than ssThresh with CRB"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new PrrRecoveryTest(
                         1000,
                         500,
@@ -197,7 +197,7 @@
                         1000,
                         "CRB",
                         "Prr test on cWnd when bytesInFlight is lower than ssThresh with CRB"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-rate-ops-test.cc ns-3.42/src/internet/test/tcp-rate-ops-test.cc
--- ns-3.41/src/internet/test/tcp-rate-ops-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-rate-ops-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -36,7 +36,7 @@
 class MimicCongControl;
 
 /**
- * \ingroup internet-tests
+ * \ingroup internet-test
  * \ingroup tests
  *
  * \brief The TcpRateLinux Basic Test
@@ -217,7 +217,7 @@
 }
 
 /**
- * \ingroup internet-tests
+ * \ingroup internet-test
  * \ingroup tests
  *
  * \brief The TcpRateLinux Test uses sender-receiver model to test its functionality.
@@ -435,7 +435,7 @@
 }
 
 /**
- * \ingroup internet-tests
+ * \ingroup internet-test
  * \ingroup tests
  *
  * \brief The TcpRateLinuxWithBufferTest tests rate sample functionality with arbitrary SACK
@@ -601,21 +601,21 @@
 {
   public:
     TcpRateOpsTestSuite()
-        : TestSuite("tcp-rate-ops", UNIT)
+        : TestSuite("tcp-rate-ops", Type::UNIT)
     {
         AddTestCase(new TcpRateLinuxBasicTest(1000,
                                               SequenceNumber32(20),
                                               SequenceNumber32(11),
                                               1,
                                               "Testing SkbDelivered and SkbSent"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpRateLinuxBasicTest(1000,
                                       SequenceNumber32(11),
                                       SequenceNumber32(11),
                                       2,
                                       "Testing SkbDelivered and SkbSent with app limited data"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         std::vector<uint32_t> toDrop;
         toDrop.push_back(4001);
@@ -623,35 +623,35 @@
             new TcpRateLinuxWithSocketsTest("Checking Rate sample value without SACK, one drop",
                                             false,
                                             toDrop),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpRateLinuxWithSocketsTest("Checking Rate sample value with SACK, one drop",
                                             true,
                                             toDrop),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         toDrop.push_back(4001);
         AddTestCase(
             new TcpRateLinuxWithSocketsTest("Checking Rate sample value without SACK, two drop",
                                             false,
                                             toDrop),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpRateLinuxWithSocketsTest("Checking Rate sample value with SACK, two drop",
                                             true,
                                             toDrop),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpRateLinuxWithBufferTest(1000,
                                            "Checking rate sample values with arbitrary SACK Block"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(
             new TcpRateLinuxWithBufferTest(500,
                                            "Checking rate sample values with arbitrary SACK Block"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-rto-test.cc ns-3.42/src/internet/test/tcp-rto-test.cc
--- ns-3.41/src/internet/test/tcp-rto-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-rto-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -514,7 +514,7 @@
 {
   public:
     TcpRtoTestSuite()
-        : TestSuite("tcp-rto-test", UNIT)
+        : TestSuite("tcp-rto-test", Type::UNIT)
     {
         std::list<TypeId> types = {
             TcpNewReno::GetTypeId(),
@@ -523,7 +523,7 @@
         for (const auto& t : types)
         {
             AddTestCase(new TcpRtoTest(t, t.GetName() + " RTO retransmit testing"),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
 
             constexpr uint32_t seqToDrop = 25001;
 
@@ -532,7 +532,7 @@
                                                seqToDrop,
                                                Seconds(0.5),
                                                t.GetName() + " RTO ssthresh testing, set to 2*MSL"),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
 
             // With RTO of 0.005 seconds, FlightSize/2 > 2*SMSS
             AddTestCase(new TcpSsThreshRtoTest(
@@ -540,10 +540,10 @@
                             seqToDrop,
                             Seconds(0.005),
                             t.GetName() + " RTO ssthresh testing, set to half of BytesInFlight"),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
 
             AddTestCase(new TcpTimeRtoTest(t, t.GetName() + " RTO timing testing"),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
         }
     }
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-rtt-estimation.cc ns-3.42/src/internet/test/tcp-rtt-estimation.cc
--- ns-3.41/src/internet/test/tcp-rtt-estimation.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-rtt-estimation.cc	2024-05-29 15:29:46.972073300 -0700
@@ -249,16 +249,16 @@
 {
   public:
     TcpRttEstimationTestSuite()
-        : TestSuite("tcp-rtt-estimation-test", UNIT)
+        : TestSuite("tcp-rtt-estimation-test", Type::UNIT)
     {
         AddTestCase(new TcpRttEstimationTest("RTT estimation, ts, no data", true, 0),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpRttEstimationTest("RTT estimation, no ts, no data", false, 0),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpRttEstimationTest("RTT estimation, ts, some data", true, 10),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpRttEstimationTest("RTT estimation, no ts, some data", false, 10),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         std::vector<uint32_t> toDrop;
         toDrop.push_back(501);
@@ -268,13 +268,13 @@
                                                      false,
                                                      10,
                                                      toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpRttEstimationWithLossTest("RTT estimation, ts,"
                                                      " some data, with retr",
                                                      true,
                                                      10,
                                                      toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         toDrop.push_back(501);
         AddTestCase(new TcpRttEstimationWithLossTest("RTT estimation, no ts,"
@@ -282,13 +282,13 @@
                                                      false,
                                                      10,
                                                      toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpRttEstimationWithLossTest("RTT estimation, ts,"
                                                      " some data, with retr",
                                                      true,
                                                      10,
                                                      toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         toDrop.push_back(54001);
         toDrop.push_back(58001);
@@ -300,13 +300,13 @@
                                                      false,
                                                      1000,
                                                      toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpRttEstimationWithLossTest("RTT estimation, ts,"
                                                      " a lot of data, with retr",
                                                      true,
                                                      1000,
                                                      toDrop),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-rx-buffer-test.cc ns-3.42/src/internet/test/tcp-rx-buffer-test.cc
--- ns-3.41/src/internet/test/tcp-rx-buffer-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-rx-buffer-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -24,7 +24,7 @@
 NS_LOG_COMPONENT_DEFINE("TcpRxBufferTestSuite");
 
 /**
- * \ingroup internet-tests
+ * \ingroup internet-test
  * \ingroup tests
  *
  * \brief The TcpRxBuffer Test
@@ -302,9 +302,9 @@
 {
   public:
     TcpRxBufferTestSuite()
-        : TestSuite("tcp-rx-buffer", UNIT)
+        : TestSuite("tcp-rx-buffer", Type::UNIT)
     {
-        AddTestCase(new TcpRxBufferTestCase, TestCase::QUICK);
+        AddTestCase(new TcpRxBufferTestCase, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-sack-permitted-test.cc ns-3.42/src/internet/test/tcp-sack-permitted-test.cc
--- ns-3.41/src/internet/test/tcp-sack-permitted-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-sack-permitted-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -101,17 +101,11 @@
     switch (m_configuration)
     {
     case DISABLED:
-        socket->SetAttribute("Sack", BooleanValue(false));
-        break;
-
     case ENABLED_RECEIVER:
         socket->SetAttribute("Sack", BooleanValue(false));
         break;
 
     case ENABLED_SENDER:
-        socket->SetAttribute("Sack", BooleanValue(true));
-        break;
-
     case ENABLED:
         socket->SetAttribute("Sack", BooleanValue(true));
         break;
@@ -213,14 +207,16 @@
   public:
     /** \brief Constructor */
     TcpSackPermittedTestSuite()
-        : TestSuite("tcp-sack-permitted", UNIT)
+        : TestSuite("tcp-sack-permitted", Type::UNIT)
     {
-        AddTestCase(new SackPermittedTestCase(SackPermittedTestCase::DISABLED), TestCase::QUICK);
+        AddTestCase(new SackPermittedTestCase(SackPermittedTestCase::DISABLED),
+                    TestCase::Duration::QUICK);
         AddTestCase(new SackPermittedTestCase(SackPermittedTestCase::ENABLED_RECEIVER),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SackPermittedTestCase(SackPermittedTestCase::ENABLED_SENDER),
-                    TestCase::QUICK);
-        AddTestCase(new SackPermittedTestCase(SackPermittedTestCase::ENABLED), TestCase::QUICK);
+                    TestCase::Duration::QUICK);
+        AddTestCase(new SackPermittedTestCase(SackPermittedTestCase::ENABLED),
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-scalable-test.cc ns-3.42/src/internet/test/tcp-scalable-test.cc
--- ns-3.41/src/internet/test/tcp-scalable-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-scalable-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -170,7 +170,7 @@
 {
   public:
     TcpScalableTestSuite()
-        : TestSuite("tcp-scalable-test", UNIT)
+        : TestSuite("tcp-scalable-test", Type::UNIT)
     {
         AddTestCase(
             new TcpScalableIncrementTest(
@@ -178,38 +178,38 @@
                 536,
                 38,
                 "Scalable increment test on cWnd = 38 segments and segmentSize = 536 bytes"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new TcpScalableIncrementTest(
                         38,
                         1,
                         100,
                         "Scalable increment test on cWnd = 38 segments and segmentSize = 1 byte"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpScalableIncrementTest(
                 53 * 1446,
                 1446,
                 50,
                 "Scalable increment test on cWnd = 53 segments and segmentSize = 1446 bytes"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
 
         AddTestCase(new TcpScalableDecrementTest(
                         38,
                         1,
                         "Scalable decrement test on cWnd = 38 segments and segmentSize = 1 byte"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new TcpScalableDecrementTest(
                 100 * 536,
                 536,
                 "Scalable decrement test on cWnd = 100 segments and segmentSize = 536 bytes"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new TcpScalableDecrementTest(
                 40 * 1446,
                 1446,
                 "Scalable decrement test on cWnd = 40 segments and segmentSize = 1446 bytes"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-slow-start-test.cc ns-3.42/src/internet/test/tcp-slow-start-test.cc
--- ns-3.41/src/internet/test/tcp-slow-start-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-slow-start-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -267,7 +267,7 @@
 {
   public:
     TcpSlowStartTestSuite()
-        : TestSuite("tcp-slow-start-test", UNIT)
+        : TestSuite("tcp-slow-start-test", Type::UNIT)
     {
         // This test have less packets to transmit than SsTh
         std::list<TypeId> types = {
@@ -284,21 +284,21 @@
                                                    10,
                                                    t,
                                                    "slow start 500 byte, " + typeName),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new TcpSlowStartNormalTest(1000,
                                                    1000,
                                                    10000,
                                                    9,
                                                    t,
                                                    "slow start 1000 byte, " + typeName),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new TcpSlowStartNormalTest(500,
                                                    250,
                                                    10000,
                                                    10,
                                                    t,
                                                    "slow start small packets, " + typeName),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpSlowStartAttackerTest(500,
                                              500,
@@ -306,7 +306,7 @@
                                              10,
                                              t,
                                              "slow start ack attacker, 500 byte, " + typeName),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new TcpSlowStartAttackerTest(1000,
                                              1000,
@@ -314,7 +314,7 @@
                                              9,
                                              t,
                                              "slow start ack attacker, 1000 byte, " + typeName),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
         }
     }
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-syn-connection-failed-test.cc ns-3.42/src/internet/test/tcp-syn-connection-failed-test.cc
--- ns-3.41/src/internet/test/tcp-syn-connection-failed-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-syn-connection-failed-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -102,12 +102,12 @@
 {
   public:
     TcpSynConnectionFailedTestSuite()
-        : TestSuite("tcp-syn-connection-failed-test", UNIT)
+        : TestSuite("tcp-syn-connection-failed-test", Type::UNIT)
     {
         AddTestCase(new TcpSynConnectionFailedTest("TCP SYN connection failed test no ECN", false),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpSynConnectionFailedTest("TCP SYN connection failed test with ECN", true),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-test.cc ns-3.42/src/internet/test/tcp-test.cc
--- ns-3.41/src/internet/test/tcp-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -543,19 +543,19 @@
 {
   public:
     TcpTestSuite()
-        : TestSuite("tcp", UNIT)
+        : TestSuite("tcp", Type::UNIT)
     {
         // Arguments to these test cases are 1) totalStreamSize,
         // 2) source write size, 3) source read size
         // 4) server write size, and 5) server read size
         // with units of bytes
-        AddTestCase(new TcpTestCase(13, 200, 200, 200, 200, false), TestCase::QUICK);
-        AddTestCase(new TcpTestCase(13, 1, 1, 1, 1, false), TestCase::QUICK);
-        AddTestCase(new TcpTestCase(100000, 100, 50, 100, 20, false), TestCase::QUICK);
+        AddTestCase(new TcpTestCase(13, 200, 200, 200, 200, false), TestCase::Duration::QUICK);
+        AddTestCase(new TcpTestCase(13, 1, 1, 1, 1, false), TestCase::Duration::QUICK);
+        AddTestCase(new TcpTestCase(100000, 100, 50, 100, 20, false), TestCase::Duration::QUICK);
 
-        AddTestCase(new TcpTestCase(13, 200, 200, 200, 200, true), TestCase::QUICK);
-        AddTestCase(new TcpTestCase(13, 1, 1, 1, 1, true), TestCase::QUICK);
-        AddTestCase(new TcpTestCase(100000, 100, 50, 100, 20, true), TestCase::QUICK);
+        AddTestCase(new TcpTestCase(13, 200, 200, 200, 200, true), TestCase::Duration::QUICK);
+        AddTestCase(new TcpTestCase(13, 1, 1, 1, 1, true), TestCase::Duration::QUICK);
+        AddTestCase(new TcpTestCase(100000, 100, 50, 100, 20, true), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-timestamp-test.cc ns-3.42/src/internet/test/tcp-timestamp-test.cc
--- ns-3.41/src/internet/test/tcp-timestamp-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-timestamp-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -103,17 +103,11 @@
     switch (m_configuration)
     {
     case DISABLED:
-        socket->SetAttribute("Timestamp", BooleanValue(false));
-        break;
-
     case ENABLED_RECEIVER:
         socket->SetAttribute("Timestamp", BooleanValue(false));
         break;
 
     case ENABLED_SENDER:
-        socket->SetAttribute("Timestamp", BooleanValue(true));
-        break;
-
     case ENABLED:
         socket->SetAttribute("Timestamp", BooleanValue(true));
         break;
@@ -199,12 +193,12 @@
 void
 TimestampTestCase::Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who)
 {
-    if (who == SENDER)
-    {
-    }
-    else if (who == RECEIVER)
-    {
-    }
+    // if (who == SENDER)
+    // {
+    // }
+    // else if (who == RECEIVER)
+    // {
+    // }
 }
 
 /**
@@ -296,17 +290,20 @@
 {
   public:
     TcpTimestampTestSuite()
-        : TestSuite("tcp-timestamp", UNIT)
+        : TestSuite("tcp-timestamp", Type::UNIT)
     {
-        AddTestCase(new TimestampTestCase(TimestampTestCase::DISABLED), TestCase::QUICK);
-        AddTestCase(new TimestampTestCase(TimestampTestCase::ENABLED_RECEIVER), TestCase::QUICK);
-        AddTestCase(new TimestampTestCase(TimestampTestCase::ENABLED_SENDER), TestCase::QUICK);
-        AddTestCase(new TimestampTestCase(TimestampTestCase::ENABLED), TestCase::QUICK);
-        AddTestCase(new TimestampValueTestCase(0.0, 0.01, "Value Check"), TestCase::QUICK);
-        AddTestCase(new TimestampValueTestCase(3.0, 0.5, "Value Check"), TestCase::QUICK);
-        AddTestCase(new TimestampValueTestCase(5.5, 1.0, "Value Check"), TestCase::QUICK);
-        AddTestCase(new TimestampValueTestCase(6.0, 2.0, "Value Check"), TestCase::QUICK);
-        AddTestCase(new TimestampValueTestCase(2.4, 0.7, "Value Check"), TestCase::QUICK);
+        AddTestCase(new TimestampTestCase(TimestampTestCase::DISABLED), TestCase::Duration::QUICK);
+        AddTestCase(new TimestampTestCase(TimestampTestCase::ENABLED_RECEIVER),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TimestampTestCase(TimestampTestCase::ENABLED_SENDER),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TimestampTestCase(TimestampTestCase::ENABLED), TestCase::Duration::QUICK);
+        AddTestCase(new TimestampValueTestCase(0.0, 0.01, "Value Check"),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TimestampValueTestCase(3.0, 0.5, "Value Check"), TestCase::Duration::QUICK);
+        AddTestCase(new TimestampValueTestCase(5.5, 1.0, "Value Check"), TestCase::Duration::QUICK);
+        AddTestCase(new TimestampValueTestCase(6.0, 2.0, "Value Check"), TestCase::Duration::QUICK);
+        AddTestCase(new TimestampValueTestCase(2.4, 0.7, "Value Check"), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-tx-buffer-test.cc ns-3.42/src/internet/test/tcp-tx-buffer-test.cc
--- ns-3.41/src/internet/test/tcp-tx-buffer-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-tx-buffer-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -27,7 +27,7 @@
 NS_LOG_COMPONENT_DEFINE("TcpTxBufferTestSuite");
 
 /**
- * \ingroup internet-tests
+ * \ingroup internet-test
  * \ingroup tests
  *
  * \brief The TcpTxBuffer Test
@@ -439,9 +439,9 @@
 {
   public:
     TcpTxBufferTestSuite()
-        : TestSuite("tcp-tx-buffer", UNIT)
+        : TestSuite("tcp-tx-buffer", Type::UNIT)
     {
-        AddTestCase(new TcpTxBufferTestCase, TestCase::QUICK);
+        AddTestCase(new TcpTxBufferTestCase, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-vegas-test.cc ns-3.42/src/internet/test/tcp-vegas-test.cc
--- ns-3.41/src/internet/test/tcp-vegas-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-vegas-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -209,7 +209,7 @@
 {
   public:
     TcpVegasTestSuite()
-        : TestSuite("tcp-vegas-test", UNIT)
+        : TestSuite("tcp-vegas-test", Type::UNIT)
     {
         AddTestCase(
             new TcpVegasTest(38 * 1446,
@@ -220,7 +220,7 @@
                              SequenceNumber32(2893),
                              SequenceNumber32(5785),
                              "Vegas test on cWnd and ssThresh when in slow start and diff > gamma"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new TcpVegasTest(5 * 536,
                              536,
@@ -230,7 +230,7 @@
                              SequenceNumber32(3216),
                              SequenceNumber32(3753),
                              "Vegas test on cWnd and ssThresh when in slow start and diff < gamma"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new TcpVegasTest(60 * 346,
                                      346,
                                      40 * 346,
@@ -239,7 +239,7 @@
                                      SequenceNumber32(20761),
                                      SequenceNumber32(21107),
                                      "Vegas test on cWnd and ssThresh when diff > beta"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpVegasTest(15 * 1446,
                                      1446,
                                      10 * 1446,
@@ -248,7 +248,7 @@
                                      SequenceNumber32(21691),
                                      SequenceNumber32(24583),
                                      "Vegas test on cWnd and ssThresh when diff < alpha"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpVegasTest(20 * 746,
                                      746,
                                      10 * 746,
@@ -257,7 +257,7 @@
                                      SequenceNumber32(14921),
                                      SequenceNumber32(15667),
                                      "Vegas test on cWnd and ssThresh when alpha <= diff <= beta"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-veno-test.cc ns-3.42/src/internet/test/tcp-veno-test.cc
--- ns-3.41/src/internet/test/tcp-veno-test.cc	2024-02-09 14:44:07.949790500 -0800
+++ ns-3.42/src/internet/test/tcp-veno-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -306,7 +306,7 @@
 {
   public:
     TcpVenoTestSuite()
-        : TestSuite("tcp-veno-test", UNIT)
+        : TestSuite("tcp-veno-test", Type::UNIT)
     {
         AddTestCase(new TcpVenoTest(38 * 1446,
                                     1446,
@@ -315,7 +315,7 @@
                                     1,
                                     1,
                                     "Veno test on cWnd in slow start and non-congestive loss"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpVenoTest(30 * 536,
                                     536,
                                     20 * 536,
@@ -323,7 +323,7 @@
                                     1,
                                     1,
                                     "Veno test on cWnd with diff < beta"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpVenoTest(60 * 536,
                                     536,
                                     40 * 536,
@@ -331,7 +331,7 @@
                                     1,
                                     3,
                                     "Veno increment test on cWnd with diff > beta"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-wscaling-test.cc ns-3.42/src/internet/test/tcp-wscaling-test.cc
--- ns-3.41/src/internet/test/tcp-wscaling-test.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/internet/test/tcp-wscaling-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -118,17 +118,11 @@
     switch (m_configuration)
     {
     case DISABLED:
-        socket->SetAttribute("WindowScaling", BooleanValue(false));
-        break;
-
     case ENABLED_RECEIVER:
         socket->SetAttribute("WindowScaling", BooleanValue(false));
         break;
 
     case ENABLED_SENDER:
-        socket->SetAttribute("WindowScaling", BooleanValue(true));
-        break;
-
     case ENABLED:
         socket->SetAttribute("WindowScaling", BooleanValue(true));
         break;
@@ -232,46 +226,46 @@
 {
   public:
     TcpWScalingTestSuite()
-        : TestSuite("tcp-wscaling", UNIT)
+        : TestSuite("tcp-wscaling", Type::UNIT)
     {
         AddTestCase(
             new WScalingTestCase(WScalingTestCase::ENABLED, 200000, 65535, "WS only server"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new WScalingTestCase(WScalingTestCase::ENABLED,
                                          65535,
                                          65535,
                                          "Window scaling not used, all enabled"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new WScalingTestCase(WScalingTestCase::DISABLED, 65535, 65535, "WS disabled"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new WScalingTestCase(WScalingTestCase::ENABLED_SENDER,
                                          65535,
                                          65535,
                                          "WS enabled client"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new WScalingTestCase(WScalingTestCase::ENABLED_RECEIVER,
                                          65535,
                                          65535,
                                          "WS disabled client"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         AddTestCase(
             new WScalingTestCase(WScalingTestCase::ENABLED, 65535, 200000, "WS only client"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new WScalingTestCase(WScalingTestCase::ENABLED, 131072, 65535, "WS only server"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new WScalingTestCase(WScalingTestCase::ENABLED, 65535, 131072, "WS only client"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new WScalingTestCase(WScalingTestCase::ENABLED, 4000, 4000, "WS small window, all"),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new WScalingTestCase(WScalingTestCase::ENABLED_SENDER,
                                          4000,
                                          4000,
                                          "WS small window, sender"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-yeah-test.cc ns-3.42/src/internet/test/tcp-yeah-test.cc
--- ns-3.41/src/internet/test/tcp-yeah-test.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/internet/test/tcp-yeah-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -364,7 +364,7 @@
 {
   public:
     TcpYeahTestSuite()
-        : TestSuite("tcp-yeah-test", UNIT)
+        : TestSuite("tcp-yeah-test", Type::UNIT)
     {
         AddTestCase(new TcpYeahIncrementTest(20 * 1446,
                                              25 * 1446,
@@ -374,7 +374,7 @@
                                              1,
                                              MilliSeconds(105),
                                              "YeAH test on cWnd when in slow start"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpYeahIncrementTest(30 * 1446,
                                              25 * 1446,
                                              1446,
@@ -383,7 +383,7 @@
                                              30,
                                              MilliSeconds(105),
                                              "YeAH test on cWnd when in Fast mode"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpYeahIncrementTest(
                         40 * 356,
                         30 * 356,
@@ -393,7 +393,7 @@
                         1,
                         MilliSeconds(120),
                         "YeAH test on cWnd when in slow mode without precautionary decongestion"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpYeahIncrementTest(
                         100 * 356,
                         70 * 356,
@@ -403,7 +403,7 @@
                         1,
                         MilliSeconds(600),
                         "YeAH test on cWnd when in slow mode with precautionary decongestion"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpYeahDecrementTest(
                         40 * 1446,
                         30 * 1446,
@@ -413,7 +413,7 @@
                         MilliSeconds(120),
                         UintegerValue(0),
                         "YeAH test on ssThresh upon loss while competing with Reno flows"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new TcpYeahDecrementTest(
                         57 * 1446,
                         42 * 1446,
@@ -423,7 +423,7 @@
                         MilliSeconds(200),
                         UintegerValue(2),
                         "YeAH test on ssThresh upon loss while not competing with Reno flows"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/tcp-zero-window-test.cc ns-3.42/src/internet/test/tcp-zero-window-test.cc
--- ns-3.41/src/internet/test/tcp-zero-window-test.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/internet/test/tcp-zero-window-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -236,7 +236,7 @@
         if (h.GetFlags() & TcpHeader::SYN)
         {
             EventId persistentEvent = GetPersistentEvent(SENDER);
-            NS_TEST_ASSERT_MSG_EQ(persistentEvent.IsRunning(),
+            NS_TEST_ASSERT_MSG_EQ(persistentEvent.IsPending(),
                                   true,
                                   "Persistent event not started");
         }
@@ -255,9 +255,9 @@
 {
   public:
     TcpZeroWindowTestSuite()
-        : TestSuite("tcp-zero-window-test", UNIT)
+        : TestSuite("tcp-zero-window-test", Type::UNIT)
     {
-        AddTestCase(new TcpZeroWindowTest("zero window test"), TestCase::QUICK);
+        AddTestCase(new TcpZeroWindowTest("zero window test"), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet/test/udp-test.cc ns-3.42/src/internet/test/udp-test.cc
--- ns-3.41/src/internet/test/udp-test.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/internet/test/udp-test.cc	2024-05-29 15:29:46.972073300 -0700
@@ -490,10 +490,8 @@
                                               MakeCallback(&UdpSocketImplTest::SentPkt, this));
 
     // The socket is not connected.
-    txSocket->SetIpTos(0x28); // AF11
     txSocket->SetPriority(6); // Interactive
     // Send a packet to a specified destination:
-    // - for not connected sockets, the tos specified in the destination address (0) is used
     // - since the tos is zero, the priority set for the socket is used
     SendDataTo(txSocket, "10.0.0.1");
     NS_TEST_EXPECT_MSG_EQ(m_receivedPacket->GetSize(), 123, "trivial");
@@ -504,7 +502,7 @@
     m_receivedPacket->RemoveAllByteTags();
 
     InetSocketAddress dest("10.0.0.1", 1234);
-    dest.SetTos(0xb8); // EF
+    txSocket->SetIpTos(0xb8); // EF
     // the connect operation sets the tos (and priority) for the socket
     NS_TEST_EXPECT_MSG_EQ(txSocket->Connect(dest), 0, "the connect operation failed");
 
@@ -771,12 +769,12 @@
 {
   public:
     UdpTestSuite()
-        : TestSuite("udp", UNIT)
+        : TestSuite("udp", Type::UNIT)
     {
-        AddTestCase(new UdpSocketImplTest, TestCase::QUICK);
-        AddTestCase(new UdpSocketLoopbackTest, TestCase::QUICK);
-        AddTestCase(new Udp6SocketImplTest, TestCase::QUICK);
-        AddTestCase(new Udp6SocketLoopbackTest, TestCase::QUICK);
+        AddTestCase(new UdpSocketImplTest, TestCase::Duration::QUICK);
+        AddTestCase(new UdpSocketLoopbackTest, TestCase::Duration::QUICK);
+        AddTestCase(new Udp6SocketImplTest, TestCase::Duration::QUICK);
+        AddTestCase(new Udp6SocketLoopbackTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/examples/traceroute-example.cc ns-3.42/src/internet-apps/examples/traceroute-example.cc
--- ns-3.41/src/internet-apps/examples/traceroute-example.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/examples/traceroute-example.cc	2024-05-29 15:29:46.952073000 -0700
@@ -18,8 +18,6 @@
  *
  *
  * TraceRoute application example using AODV routing protocol.
- *
- *
  */
 
 #include "ns3/aodv-module.h"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/helper/ping-helper.cc ns-3.42/src/internet-apps/helper/ping-helper.cc
--- ns-3.41/src/internet-apps/helper/ping-helper.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/helper/ping-helper.cc	2024-05-29 15:29:46.952073000 -0700
@@ -24,62 +24,19 @@
 
 #include "ping-helper.h"
 
-#include "ns3/names.h"
-#include "ns3/ping.h"
-
 namespace ns3
 {
 
 PingHelper::PingHelper()
+    : ApplicationHelper("ns3::Ping")
 {
-    m_factory.SetTypeId("ns3::Ping");
 }
 
-PingHelper::PingHelper(Address remote, Address local)
+PingHelper::PingHelper(const Address& remote, const Address& local)
+    : ApplicationHelper("ns3::Ping")
 {
-    m_factory.SetTypeId("ns3::Ping");
     m_factory.Set("Destination", AddressValue(remote));
     m_factory.Set("InterfaceAddress", AddressValue(local));
 }
 
-void
-PingHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-PingHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-PingHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-PingHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-PingHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<Ping> app = m_factory.Create<Ping>();
-    node->AddApplication(app);
-
-    return app;
-}
-
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/helper/ping-helper.h ns-3.42/src/internet-apps/helper/ping-helper.h
--- ns-3.41/src/internet-apps/helper/ping-helper.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/helper/ping-helper.h	2024-05-29 15:29:46.952073000 -0700
@@ -25,14 +25,8 @@
 #ifndef PING_HELPER_H
 #define PING_HELPER_H
 
-#include "ns3/application-container.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv6-address.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
 #include "ns3/ping.h"
-
-#include <stdint.h>
+#include <ns3/application-helper.h>
 
 namespace ns3
 {
@@ -44,7 +38,7 @@
  * This class creates one or multiple instances of ns3::Ping and associates
  * it/them to one/multiple node(s).
  */
-class PingHelper
+class PingHelper : public ApplicationHelper
 {
   public:
     /**
@@ -60,55 +54,7 @@
      * \param remote The address which should be pinged
      * \param local The source address
      */
-    PingHelper(Address remote, Address local = Address());
-
-    /**
-     * Install a Ping application on each Node in the provided NodeContainer.
-     *
-     * \param nodes The NodeContainer containing all of the nodes to get a Ping
-     *              application.
-     *
-     * \returns A list of Ping applications, one for each input node
-     */
-    ApplicationContainer Install(NodeContainer nodes) const;
-
-    /**
-     * Install a Ping application on the provided Node.  The Node is specified
-     * directly by a Ptr<Node>
-     *
-     * \param node The node to install the Ping application on.
-     *
-     * \returns An ApplicationContainer holding the Ping application created.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
-
-    /**
-     * Install a Ping application on the provided Node.  The Node is specified
-     * by a string that must have previously been associated with a Node using the
-     * Object Name Service.
-     *
-     * \param nodeName The node to install the Ping application on.
-     *
-     * \returns An ApplicationContainer holding the Ping application created.
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-    /**
-     * \brief Configure ping applications attribute
-     * \param name   attribute's name
-     * \param value  attribute's value
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-  private:
-    /**
-     * \brief Do the actual application installation in the node
-     * \param node the node
-     * \returns a Smart pointer to the installed application
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-    /// Object factory
-    ObjectFactory m_factory;
+    PingHelper(const Address& remote, const Address& local = Address());
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/helper/radvd-helper.cc ns-3.42/src/internet-apps/helper/radvd-helper.cc
--- ns-3.41/src/internet-apps/helper/radvd-helper.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/helper/radvd-helper.cc	2024-05-29 15:29:46.952073000 -0700
@@ -31,12 +31,14 @@
 NS_LOG_COMPONENT_DEFINE("RadvdHelper");
 
 RadvdHelper::RadvdHelper()
+    : ApplicationHelper(Radvd::GetTypeId())
 {
-    m_factory.SetTypeId(Radvd::GetTypeId());
 }
 
 void
-RadvdHelper::AddAnnouncedPrefix(uint32_t interface, Ipv6Address prefix, uint32_t prefixLength)
+RadvdHelper::AddAnnouncedPrefix(uint32_t interface,
+                                const Ipv6Address& prefix,
+                                uint32_t prefixLength)
 {
     NS_LOG_FUNCTION(this << int(interface) << prefix << int(prefixLength));
     if (prefixLength != 64)
@@ -109,27 +111,19 @@
     m_radvdInterfaces.clear();
 }
 
-void
-RadvdHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-RadvdHelper::Install(Ptr<Node> node)
+Ptr<Application>
+RadvdHelper::DoInstall(Ptr<Node> node)
 {
-    ApplicationContainer apps;
-    Ptr<Radvd> radvd = m_factory.Create<Radvd>();
-    for (auto iter = m_radvdInterfaces.begin(); iter != m_radvdInterfaces.end(); iter++)
+    auto radvd = m_factory.Create<Radvd>();
+    for (auto [index, interface] : m_radvdInterfaces)
     {
-        if (!iter->second->GetPrefixes().empty())
+        if (!interface->GetPrefixes().empty())
         {
-            radvd->AddConfiguration(iter->second);
+            radvd->AddConfiguration(interface);
         }
     }
     node->AddApplication(radvd);
-    apps.Add(radvd);
-    return apps;
+    return radvd;
 }
 
 } /* namespace ns3 */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/helper/radvd-helper.h ns-3.42/src/internet-apps/helper/radvd-helper.h
--- ns-3.41/src/internet-apps/helper/radvd-helper.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/helper/radvd-helper.h	2024-05-29 15:29:46.952073000 -0700
@@ -20,13 +20,9 @@
 #ifndef RADVD_HELPER_H
 #define RADVD_HELPER_H
 
-#include "ns3/application-container.h"
-#include "ns3/ipv6-address.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
 #include "ns3/radvd-interface.h"
+#include <ns3/application-helper.h>
 
-#include <list>
 #include <map>
 #include <stdint.h>
 
@@ -37,7 +33,7 @@
  * \ingroup radvd
  * \brief Radvd application helper.
  */
-class RadvdHelper
+class RadvdHelper : public ApplicationHelper
 {
   public:
     /**
@@ -51,7 +47,7 @@
      * \param prefix announced IPv6 prefix
      * \param prefixLength announced IPv6 prefix length
      */
-    void AddAnnouncedPrefix(uint32_t interface, Ipv6Address prefix, uint32_t prefixLength);
+    void AddAnnouncedPrefix(uint32_t interface, const Ipv6Address& prefix, uint32_t prefixLength);
 
     /**
      * \brief Enable the router as default router for the interface.
@@ -80,25 +76,8 @@
      */
     void ClearPrefixes();
 
-    /**
-     * \brief Set some attributes.
-     * \param name attribute name
-     * \param value attribute value
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-
-    /**
-     * \brief Install the application in a Node.
-     * \param node the Node
-     * \return application container
-     */
-    ApplicationContainer Install(Ptr<Node> node);
-
   private:
-    /**
-     * \brief An object factory.
-     */
-    ObjectFactory m_factory;
+    Ptr<Application> DoInstall(Ptr<Node> node) override;
 
     /// Container: interface index, RadvdInterface
     typedef std::map<uint32_t, Ptr<RadvdInterface>> RadvdInterfaceMap;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/helper/v4traceroute-helper.cc ns-3.42/src/internet-apps/helper/v4traceroute-helper.cc
--- ns-3.41/src/internet-apps/helper/v4traceroute-helper.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/helper/v4traceroute-helper.cc	2024-05-29 15:29:46.952073000 -0700
@@ -21,67 +21,24 @@
 
 #include "v4traceroute-helper.h"
 
-#include "ns3/names.h"
+#include "ns3/output-stream-wrapper.h"
 #include "ns3/v4traceroute.h"
 
 namespace ns3
 {
 
-V4TraceRouteHelper::V4TraceRouteHelper(Ipv4Address remote)
+V4TraceRouteHelper::V4TraceRouteHelper(const Ipv4Address& remote)
+    : ApplicationHelper("ns3::V4TraceRoute")
 {
-    m_factory.SetTypeId("ns3::V4TraceRoute");
     m_factory.Set("Remote", Ipv4AddressValue(remote));
 }
 
 void
-V4TraceRouteHelper::SetAttribute(std::string name, const AttributeValue& value)
-{
-    m_factory.Set(name, value);
-}
-
-ApplicationContainer
-V4TraceRouteHelper::Install(Ptr<Node> node) const
-{
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-V4TraceRouteHelper::Install(std::string nodeName) const
-{
-    Ptr<Node> node = Names::Find<Node>(nodeName);
-    return ApplicationContainer(InstallPriv(node));
-}
-
-ApplicationContainer
-V4TraceRouteHelper::Install(NodeContainer c) const
-{
-    ApplicationContainer apps;
-    for (auto i = c.Begin(); i != c.End(); ++i)
-    {
-        apps.Add(InstallPriv(*i));
-    }
-
-    return apps;
-}
-
-Ptr<Application>
-V4TraceRouteHelper::InstallPriv(Ptr<Node> node) const
-{
-    Ptr<V4TraceRoute> app = m_factory.Create<V4TraceRoute>();
-    node->AddApplication(app);
-
-    return app;
-}
-
-void
 V4TraceRouteHelper::PrintTraceRouteAt(Ptr<Node> node, Ptr<OutputStreamWrapper> stream)
 {
-    Ptr<V4TraceRoute> trace;
-
     for (uint32_t i = 0; i < node->GetNApplications(); ++i)
     {
-        trace = node->GetApplication(i)->GetObject<V4TraceRoute>();
-        if (trace)
+        if (auto trace = node->GetApplication(i)->GetObject<V4TraceRoute>())
         {
             *stream->GetStream() << "Tracing Route from Node " << node->GetId() << "\n";
             trace->Print(stream);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/helper/v4traceroute-helper.h ns-3.42/src/internet-apps/helper/v4traceroute-helper.h
--- ns-3.41/src/internet-apps/helper/v4traceroute-helper.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/helper/v4traceroute-helper.h	2024-05-29 15:29:46.952073000 -0700
@@ -22,14 +22,13 @@
 #ifndef V4TRACEROUTE_HELPER_H
 #define V4TRACEROUTE_HELPER_H
 
-#include "ns3/application-container.h"
-#include "ns3/node-container.h"
-#include "ns3/object-factory.h"
-#include "ns3/output-stream-wrapper.h"
+#include <ns3/application-helper.h>
 
 namespace ns3
 {
 
+class OutputStreamWrapper;
+
 /**
  * \ingroup v4traceroute
  * \brief Create a IPv4 traceroute application and associate it to a node
@@ -37,7 +36,7 @@
  * This class creates one or multiple instances of ns3::V4TraceRoute and associates
  * it/them to one/multiple node(s).
  */
-class V4TraceRouteHelper
+class V4TraceRouteHelper : public ApplicationHelper
 {
   public:
     /**
@@ -46,61 +45,14 @@
      *
      * \param remote The address which should be traced
      */
-    V4TraceRouteHelper(Ipv4Address remote);
-
-    /**
-     * Install a TraceRoute application on each Node in the provided NodeContainer.
-     *
-     * \param nodes The NodeContainer containing all of the nodes to get a V4TraceRoute
-     *              application.
-     *
-     * \returns A list of TraceRoute applications, one for each input node
-     */
-    ApplicationContainer Install(NodeContainer nodes) const;
-
-    /**
-     * Install a TraceRoute application on the provided Node.  The Node is specified
-     * directly by a Ptr<Node>
-     *
-     * \param node The node to install the V4TraceRouteApplication on.
-     *
-     * \returns An ApplicationContainer holding the TraceRoute application created.
-     */
-    ApplicationContainer Install(Ptr<Node> node) const;
+    V4TraceRouteHelper(const Ipv4Address& remote);
 
     /**
-     * Install a TraceRoute application on the provided Node.  The Node is specified
-     * by a string that must have previously been associated with a Node using the
-     * Object Name Service.
-     *
-     * \param nodeName The node to install the V4TraceRouteApplication on.
-     *
-     * \returns An ApplicationContainer holding the TraceRoute application created.
-     */
-    ApplicationContainer Install(std::string nodeName) const;
-
-    /**
-     * \brief Configure traceRoute applications attribute
-     * \param name   attribute's name
-     * \param value  attribute's value
-     */
-    void SetAttribute(std::string name, const AttributeValue& value);
-    /**
      * \brief Print the resulting trace routes from given node.
      * \param node The origin node where the traceroute is initiated.
      * \param stream The outputstream used to print the resulting traced routes.
      */
     static void PrintTraceRouteAt(Ptr<Node> node, Ptr<OutputStreamWrapper> stream);
-
-  private:
-    /**
-     * \brief Do the actual application installation in the node
-     * \param node the node
-     * \returns a Smart pointer to the installed application
-     */
-    Ptr<Application> InstallPriv(Ptr<Node> node) const;
-    /// Object factory
-    ObjectFactory m_factory;
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/dhcp-client.h ns-3.42/src/internet-apps/model/dhcp-client.h
--- ns-3.41/src/internet-apps/model/dhcp-client.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/dhcp-client.h	2024-05-29 15:29:46.952073000 -0700
@@ -80,20 +80,15 @@
      */
     Ipv4Address GetDhcpServer();
 
-    /**
-     * Assign a fixed random variable stream number to the random variables
-     * used by this model. Return the number of streams (possibly zero) that
-     * have been assigned.
-     *
-     * \param stream First stream index to use
-     * \return the number of stream indices assigned by this model
-     */
-    int64_t AssignStreams(int64_t stream);
+    int64_t AssignStreams(int64_t stream) override;
 
   protected:
     void DoDispose() override;
 
   private:
+    void StartApplication() override;
+    void StopApplication() override;
+
     /// client states
     enum States
     {
@@ -104,16 +99,6 @@
 
     static const int DHCP_PEER_PORT = 67; //!< DHCP server port
 
-    /*
-     * \brief Starts the DHCP client application
-     */
-    void StartApplication() override;
-
-    /*
-     * \brief Stops the DHCP client application
-     */
-    void StopApplication() override;
-
     /**
      * \brief Handles changes in LinkState
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/dhcp-server.h ns-3.42/src/internet-apps/model/dhcp-server.h
--- ns-3.41/src/internet-apps/model/dhcp-server.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/dhcp-server.h	2024-05-29 15:29:46.952073000 -0700
@@ -68,6 +68,9 @@
     void DoDispose() override;
 
   private:
+    void StartApplication() override;
+    void StopApplication() override;
+
     static const int PORT = 67; //!< Port number of DHCP server
 
     /**
@@ -97,16 +100,6 @@
      */
     void TimerHandler();
 
-    /**
-     * \brief Starts the DHCP Server application
-     */
-    void StartApplication() override;
-
-    /**
-     * \brief Stops the DHCP client application
-     */
-    void StopApplication() override;
-
     Ptr<Socket> m_socket;      //!< The socket bound to port 67
     Ipv4Address m_poolAddress; //!< The network address available to the server
     Ipv4Address m_minAddress;  //!< The first address in the address pool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/ping.cc ns-3.42/src/internet-apps/model/ping.cc
--- ns-3.41/src/internet-apps/model/ping.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/ping.cc	2024-05-29 15:29:46.952073000 -0700
@@ -462,7 +462,6 @@
         }
         p->AddHeader(header);
         auto dest = InetSocketAddress(Ipv4Address::ConvertFrom(m_destination), 0);
-        dest.SetTos(m_tos);
         returnValue = m_socket->SendTo(p, 0, dest);
     }
     else
@@ -563,6 +562,7 @@
         NS_ASSERT_MSG(m_socket, "Ping::StartApplication: can not create socket.");
         m_socket->SetAttribute("Protocol", UintegerValue(1)); // icmp
         m_socket->SetRecvCallback(MakeCallback(&Ping::Receive, this));
+        m_socket->SetIpTos(m_tos);
         m_useIpv6 = false;
 
         Ipv4Address dst = Ipv4Address::ConvertFrom(m_destination);
@@ -626,11 +626,11 @@
 Ping::StopApplication()
 {
     NS_LOG_FUNCTION(this);
-    if (m_stopEvent.IsRunning())
+    if (m_stopEvent.IsPending())
     {
         m_stopEvent.Cancel();
     }
-    if (m_next.IsRunning())
+    if (m_next.IsPending())
     {
         m_next.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/ping.h ns-3.42/src/internet-apps/model/ping.h
--- ns-3.41/src/internet-apps/model/ping.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/ping.h	2024-05-29 15:29:46.952073000 -0700
@@ -147,7 +147,13 @@
      */
     typedef void (*ReportTrace)(const PingReport& report);
 
+  protected:
+    void DoDispose() override;
+
   private:
+    void StartApplication() override;
+    void StopApplication() override;
+
     /**
      * \brief Writes data to buffer in little-endian format.
      *
@@ -166,11 +172,6 @@
      */
     uint64_t Read64(const uint8_t* buffer);
 
-    // inherited from Application base class.
-    void StartApplication() override;
-    void StopApplication() override;
-    void DoDispose() override;
-
     /**
      * \brief Return the application signatiure.
      * \returns the application signature.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/radvd.cc ns-3.42/src/internet-apps/model/radvd.cc
--- ns-3.41/src/internet-apps/model/radvd.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/radvd.cc	2024-05-29 15:29:46.952073000 -0700
@@ -369,7 +369,7 @@
                         if (m_solicitedEventIds.find((*it)->GetInterface()) !=
                             m_solicitedEventIds.end())
                         {
-                            if (m_solicitedEventIds[(*it)->GetInterface()].IsRunning())
+                            if (m_solicitedEventIds[(*it)->GetInterface()].IsPending())
                             {
                                 scheduleSingle = false;
                             }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/radvd.h ns-3.42/src/internet-apps/model/radvd.h
--- ns-3.41/src/internet-apps/model/radvd.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/radvd.h	2024-05-29 15:29:46.952073000 -0700
@@ -85,23 +85,15 @@
      */
     void AddConfiguration(Ptr<RadvdInterface> routerInterface);
 
-    /**
-     * Assign a fixed random variable stream number to the random variables
-     * used by this model.  Return the number of streams (possibly zero) that
-     * have been assigned.
-     *
-     * \param stream first stream index to use
-     * \return the number of stream indices assigned by this model
-     */
-    int64_t AssignStreams(int64_t stream);
+    int64_t AssignStreams(int64_t stream) override;
 
   protected:
-    /**
-     * \brief Dispose the instance.
-     */
     void DoDispose() override;
 
   private:
+    void StartApplication() override;
+    void StopApplication() override;
+
     /// Container: Ptr to RadvdInterface
     typedef std::list<Ptr<RadvdInterface>> RadvdInterfaceList;
     /// Container Iterator: Ptr to RadvdInterface
@@ -124,16 +116,6 @@
     typedef std::map<uint32_t, Ptr<Socket>>::const_iterator SocketMapCI;
 
     /**
-     * \brief Start the application.
-     */
-    void StartApplication() override;
-
-    /**
-     * \brief Stop the application.
-     */
-    void StopApplication() override;
-
-    /**
      * \brief Send a packet.
      * \param config interface configuration
      * \param dst destination address (default ff02::1)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/v4traceroute.cc ns-3.42/src/internet-apps/model/v4traceroute.cc
--- ns-3.41/src/internet-apps/model/v4traceroute.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/v4traceroute.cc	2024-05-29 15:29:46.952073000 -0700
@@ -45,46 +45,53 @@
 TypeId
 V4TraceRoute::GetTypeId()
 {
-    static TypeId tid = TypeId("ns3::V4TraceRoute")
-                            .SetParent<Application>()
-                            .SetGroupName("Internet-Apps")
-                            .AddConstructor<V4TraceRoute>()
-                            .AddAttribute("Remote",
-                                          "The address of the machine we want to trace.",
-                                          Ipv4AddressValue(),
-                                          MakeIpv4AddressAccessor(&V4TraceRoute::m_remote),
-                                          MakeIpv4AddressChecker())
-                            .AddAttribute("Verbose",
-                                          "Produce usual output.",
-                                          BooleanValue(true),
-                                          MakeBooleanAccessor(&V4TraceRoute::m_verbose),
-                                          MakeBooleanChecker())
-                            .AddAttribute("Interval",
-                                          "Wait interval between sent packets.",
-                                          TimeValue(Seconds(0)),
-                                          MakeTimeAccessor(&V4TraceRoute::m_interval),
-                                          MakeTimeChecker())
-                            .AddAttribute("Size",
-                                          "The number of data bytes to be sent, real packet will "
-                                          "be 8 (ICMP) + 20 (IP) bytes longer.",
-                                          UintegerValue(56),
-                                          MakeUintegerAccessor(&V4TraceRoute::m_size),
-                                          MakeUintegerChecker<uint32_t>())
-                            .AddAttribute("MaxHop",
-                                          "The maximum number of hops to trace.",
-                                          UintegerValue(30),
-                                          MakeUintegerAccessor(&V4TraceRoute::m_maxTtl),
-                                          MakeUintegerChecker<uint32_t>())
-                            .AddAttribute("ProbeNum",
-                                          "The number of packets send to each hop.",
-                                          UintegerValue(3),
-                                          MakeUintegerAccessor(&V4TraceRoute::m_maxProbes),
-                                          MakeUintegerChecker<uint16_t>())
-                            .AddAttribute("Timeout",
-                                          "The waiting time for a route response before a timeout.",
-                                          TimeValue(Seconds(5)),
-                                          MakeTimeAccessor(&V4TraceRoute::m_waitIcmpReplyTimeout),
-                                          MakeTimeChecker());
+    static TypeId tid =
+        TypeId("ns3::V4TraceRoute")
+            .SetParent<Application>()
+            .SetGroupName("Internet-Apps")
+            .AddConstructor<V4TraceRoute>()
+            .AddAttribute("Remote",
+                          "The address of the machine we want to trace.",
+                          Ipv4AddressValue(),
+                          MakeIpv4AddressAccessor(&V4TraceRoute::m_remote),
+                          MakeIpv4AddressChecker())
+            .AddAttribute("Tos",
+                          "The Type of Service used to send IPv4 packets. "
+                          "All 8 bits of the TOS byte are set (including ECN bits).",
+                          UintegerValue(0),
+                          MakeUintegerAccessor(&V4TraceRoute::m_tos),
+                          MakeUintegerChecker<uint8_t>())
+            .AddAttribute("Verbose",
+                          "Produce usual output.",
+                          BooleanValue(true),
+                          MakeBooleanAccessor(&V4TraceRoute::m_verbose),
+                          MakeBooleanChecker())
+            .AddAttribute("Interval",
+                          "Wait interval between sent packets.",
+                          TimeValue(Seconds(0)),
+                          MakeTimeAccessor(&V4TraceRoute::m_interval),
+                          MakeTimeChecker())
+            .AddAttribute("Size",
+                          "The number of data bytes to be sent, real packet will "
+                          "be 8 (ICMP) + 20 (IP) bytes longer.",
+                          UintegerValue(56),
+                          MakeUintegerAccessor(&V4TraceRoute::m_size),
+                          MakeUintegerChecker<uint32_t>())
+            .AddAttribute("MaxHop",
+                          "The maximum number of hops to trace.",
+                          UintegerValue(30),
+                          MakeUintegerAccessor(&V4TraceRoute::m_maxTtl),
+                          MakeUintegerChecker<uint32_t>())
+            .AddAttribute("ProbeNum",
+                          "The number of packets send to each hop.",
+                          UintegerValue(3),
+                          MakeUintegerAccessor(&V4TraceRoute::m_maxProbes),
+                          MakeUintegerChecker<uint16_t>())
+            .AddAttribute("Timeout",
+                          "The waiting time for a route response before a timeout.",
+                          TimeValue(Seconds(5)),
+                          MakeTimeAccessor(&V4TraceRoute::m_waitIcmpReplyTimeout),
+                          MakeTimeChecker());
     return tid;
 }
 
@@ -121,6 +128,8 @@
     NS_LOG_LOGIC("Application started");
     m_started = Simulator::Now();
 
+    NS_ABORT_MSG_IF(!m_remote.IsInitialized(), "'Remote' attribute not properly set");
+
     if (m_verbose)
     {
         NS_LOG_UNCOND("Traceroute to " << m_remote << ", " << m_maxTtl << " hops Max, " << m_size
@@ -135,6 +144,7 @@
 
     m_socket = Socket::CreateSocket(GetNode(), TypeId::LookupByName("ns3::Ipv4RawSocketFactory"));
     m_socket->SetAttribute("Protocol", UintegerValue(Icmpv4L4Protocol::PROT_NUMBER));
+    m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
 
     NS_ASSERT(m_socket);
     m_socket->SetRecvCallback(MakeCallback(&V4TraceRoute::Receive, this));
@@ -152,12 +162,12 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_next.IsRunning())
+    if (m_next.IsPending())
     {
         m_next.Cancel();
     }
 
-    if (m_waitIcmpReplyTimer.IsRunning())
+    if (m_waitIcmpReplyTimer.IsPending())
     {
         m_waitIcmpReplyTimer.Cancel();
     }
@@ -183,7 +193,7 @@
 {
     NS_LOG_FUNCTION(this);
 
-    if (m_next.IsRunning() || m_waitIcmpReplyTimer.IsRunning())
+    if (m_next.IsPending() || m_waitIcmpReplyTimer.IsPending())
     {
         StopApplication();
     }
@@ -412,7 +422,7 @@
 V4TraceRoute::StartWaitReplyTimer()
 {
     NS_LOG_FUNCTION(this);
-    if (!m_waitIcmpReplyTimer.IsRunning())
+    if (!m_waitIcmpReplyTimer.IsPending())
     {
         NS_LOG_LOGIC("Starting WaitIcmpReplyTimer at " << Simulator::Now() << " for "
                                                        << m_waitIcmpReplyTimeout);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/model/v4traceroute.h ns-3.42/src/internet-apps/model/v4traceroute.h
--- ns-3.41/src/internet-apps/model/v4traceroute.h	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/model/v4traceroute.h	2024-05-29 15:29:46.952073000 -0700
@@ -63,10 +63,13 @@
      */
     void Print(Ptr<OutputStreamWrapper> stream);
 
+  protected:
+    void DoDispose() override;
+
   private:
     void StartApplication() override;
     void StopApplication() override;
-    void DoDispose() override;
+
     /**
      * \brief Return the application ID in the node.
      * \returns the application id
@@ -118,6 +121,8 @@
     uint16_t m_maxProbes;
     /// The current TTL value
     uint16_t m_ttl;
+    /// The packets Type of Service
+    uint8_t m_tos;
     /// The maximum Ttl (Max number of hops to trace)
     uint32_t m_maxTtl;
     /// The wait time until the response is considered lost.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/test/dhcp-test.cc ns-3.42/src/internet-apps/test/dhcp-test.cc
--- ns-3.41/src/internet-apps/test/dhcp-test.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/test/dhcp-test.cc	2024-05-29 15:29:46.952073000 -0700
@@ -168,9 +168,9 @@
 };
 
 DhcpTestSuite::DhcpTestSuite()
-    : TestSuite("dhcp", UNIT)
+    : TestSuite("dhcp", Type::UNIT)
 {
-    AddTestCase(new DhcpTestCase, TestCase::QUICK);
+    AddTestCase(new DhcpTestCase, TestCase::Duration::QUICK);
 }
 
 static DhcpTestSuite dhcpTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/test/ipv6-radvd-test.cc ns-3.42/src/internet-apps/test/ipv6-radvd-test.cc
--- ns-3.41/src/internet-apps/test/ipv6-radvd-test.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/test/ipv6-radvd-test.cc	2024-05-29 15:29:46.952073000 -0700
@@ -309,9 +309,9 @@
 };
 
 RadvdTestSuite::RadvdTestSuite()
-    : TestSuite("radvd", UNIT)
+    : TestSuite("radvd", Type::UNIT)
 {
-    AddTestCase(new RadvdTestCase, TestCase::QUICK);
+    AddTestCase(new RadvdTestCase, TestCase::Duration::QUICK);
 }
 
 static RadvdTestSuite radvdTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/internet-apps/test/ping-test.cc ns-3.42/src/internet-apps/test/ping-test.cc
--- ns-3.41/src/internet-apps/test/ping-test.cc	2024-02-09 14:44:07.913790200 -0800
+++ ns-3.42/src/internet-apps/test/ping-test.cc	2024-05-29 15:29:46.952073000 -0700
@@ -567,7 +567,7 @@
 };
 
 PingTestSuite::PingTestSuite()
-    : TestSuite("ping", UNIT)
+    : TestSuite("ping", Type::UNIT)
 {
     // 1. Unlimited pings, no losses, StopApplication () with no packets in flight
     //    Configuration:  Ping::Count = 0,  Ping::Interval = 1s, Ping start
@@ -586,7 +586,7 @@
     testcase1v4->CheckReportReceived(5);
     testcase1v4->CheckTraceTx(5);
     testcase1v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
-    AddTestCase(testcase1v4, TestCase::QUICK);
+    AddTestCase(testcase1v4, TestCase::Duration::QUICK);
 
     auto testcase1v6 = new PingTestCase(
         "1. Unlimited pings, no losses, StopApplication () with no packets in flight IPv6",
@@ -598,7 +598,7 @@
     testcase1v6->CheckReportReceived(5);
     testcase1v6->CheckTraceTx(5);
     testcase1v6->SetDestinationAddress(Ipv6Address("2001:1::200:ff:fe00:2"));
-    AddTestCase(testcase1v6, TestCase::QUICK);
+    AddTestCase(testcase1v6, TestCase::Duration::QUICK);
 
     // 2. Unlimited pings, no losses, StopApplication () with 1 packet in flight
     // Configuration:  Ping::Count = 0,  Ping::Interval = 1s, Ping start time =
@@ -617,7 +617,7 @@
     testcase2v4->CheckReportTransmitted(1);
     testcase2v4->CheckReportReceived(0);
     testcase1v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
-    AddTestCase(testcase2v4, TestCase::QUICK);
+    AddTestCase(testcase2v4, TestCase::Duration::QUICK);
 
     auto testcase2v6 = new PingTestCase(
         "2. Unlimited pings, no losses, StopApplication () with 1 packet in flight IPv6",
@@ -628,7 +628,7 @@
     testcase2v6->CheckReportTransmitted(1);
     testcase2v6->CheckReportReceived(0);
     testcase2v6->SetDestinationAddress(Ipv6Address("2001:1::200:ff:fe00:2"));
-    AddTestCase(testcase2v6, TestCase::QUICK);
+    AddTestCase(testcase2v6, TestCase::Duration::QUICK);
 
     // 3. Test for operation of count attribute and the resulting StopApplication time after all
     // pings were received. Limited pings, no losses, StopApplication () with no packet in flight
@@ -657,7 +657,7 @@
     testcase3v4->CheckReportTime(MicroSeconds(2020001));
     testcase3v4->CheckTraceTx(expectedTx);
     testcase3v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
-    AddTestCase(testcase3v4, TestCase::QUICK);
+    AddTestCase(testcase3v4, TestCase::Duration::QUICK);
 
     auto testcase3v6 = new PingTestCase("3. Test for operation of count attribute and exit "
                                         "time after all pings were received, IPv6",
@@ -671,7 +671,7 @@
     testcase3v6->CheckReportTime(MicroSeconds(2020001));
     testcase3v6->CheckTraceTx(expectedTx);
     testcase3v6->SetDestinationAddress(Ipv6Address("2001:1::200:ff:fe00:2"));
-    AddTestCase(testcase3v6, TestCase::QUICK);
+    AddTestCase(testcase3v6, TestCase::Duration::QUICK);
 
     // 4. Test for the operation of interval attribute for IPv4
     // Unlimited pings, no losses, StopApplication () with no packet in flight
@@ -692,7 +692,7 @@
     testcase4v4->CheckReportTransmitted(2);
     testcase4v4->CheckReportReceived(2);
     testcase4v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
-    AddTestCase(testcase4v4, TestCase::QUICK);
+    AddTestCase(testcase4v4, TestCase::Duration::QUICK);
 
     auto testcase4v6 =
         new PingTestCase("4. Test for the operation of interval attribute for IPv6", USEIPV6_TRUE);
@@ -703,7 +703,7 @@
     testcase4v6->CheckReportTransmitted(2);
     testcase4v6->CheckReportReceived(2);
     testcase4v6->SetDestinationAddress(Ipv6Address("2001:1::200:ff:fe00:2"));
-    AddTestCase(testcase4v6, TestCase::QUICK);
+    AddTestCase(testcase4v6, TestCase::Duration::QUICK);
 
     // 5. Test for behavior of pinging an unreachable host when the
     //    network does not send an ICMP unreachable message.
@@ -730,7 +730,7 @@
     testcase5v4->CheckReportTransmitted(5);
     testcase5v4->CheckReportReceived(0);
     testcase5v4->CheckReportLoss(100);
-    AddTestCase(testcase5v4, TestCase::QUICK);
+    AddTestCase(testcase5v4, TestCase::Duration::QUICK);
 
     auto testcase5v6 =
         new PingTestCase("5. Test for behavior of ping to unreachable IPv6 address", USEIPV6_TRUE);
@@ -740,7 +740,7 @@
     testcase5v6->CheckReportTransmitted(5);
     testcase5v6->CheckReportReceived(0);
     testcase5v6->CheckReportLoss(100);
-    AddTestCase(testcase5v6, TestCase::QUICK);
+    AddTestCase(testcase5v6, TestCase::Duration::QUICK);
 
     // 6. Test for behavior of pinging an broadcast (or multicast) address.
     // Limited pings, no losses, StopApplication () with no packet in flight
@@ -763,7 +763,7 @@
     testcase6v4->CheckReportTransmitted(5);
     testcase6v4->CheckReportReceived(5);
     testcase6v4->CheckReportLoss(0);
-    AddTestCase(testcase6v4, TestCase::QUICK);
+    AddTestCase(testcase6v4, TestCase::Duration::QUICK);
 
     auto testcase6v6 =
         new PingTestCase("6. Test for behavior of ping to all-nodes multicast IPv6 address",
@@ -774,7 +774,7 @@
     testcase6v6->CheckReportTransmitted(5);
     testcase6v6->CheckReportReceived(5);
     testcase6v6->CheckReportLoss(0);
-    AddTestCase(testcase6v6, TestCase::QUICK);
+    AddTestCase(testcase6v6, TestCase::Duration::QUICK);
 
     // 7. Test behavior of first reply lost in a count-limited configuration.
     // Limited pings, no losses, StopApplication () with no packet in flight
@@ -803,7 +803,7 @@
     testcase7v4->CheckReportReceived(2);
     testcase7v4->CheckReportLoss(33); // 33%
     testcase7v4->CheckReportTime(MicroSeconds(3040000));
-    AddTestCase(testcase7v4, TestCase::QUICK);
+    AddTestCase(testcase7v4, TestCase::Duration::QUICK);
 
     auto testcase7v6 = new PingTestCase(
         "7. Test behavior of first reply lost in a count-limited configuration, IPv6",
@@ -819,7 +819,7 @@
     testcase7v6->CheckReportReceived(2);
     testcase7v6->CheckReportLoss(33); // 33%
     testcase7v6->CheckReportTime(MicroSeconds(3040000));
-    AddTestCase(testcase7v6, TestCase::QUICK);
+    AddTestCase(testcase7v6, TestCase::Duration::QUICK);
 
     // 8. Test behavior of second reply lost in a count-limited configuration.
     // Limited pings, no losses, StopApplication () with no packet in flight
@@ -848,7 +848,7 @@
     testcase8v4->CheckReportReceived(2);
     testcase8v4->CheckReportLoss(33); // 33%
     testcase8v4->CheckReportTime(MicroSeconds(3040000));
-    AddTestCase(testcase8v4, TestCase::QUICK);
+    AddTestCase(testcase8v4, TestCase::Duration::QUICK);
 
     auto testcase8v6 = new PingTestCase(
         "8. Test behavior of second reply lost in a count-limited configuration, IPv6",
@@ -864,7 +864,7 @@
     testcase8v6->CheckReportReceived(2);
     testcase8v6->CheckReportLoss(33); // 33%
     testcase8v6->CheckReportTime(MicroSeconds(3040000));
-    AddTestCase(testcase8v6, TestCase::QUICK);
+    AddTestCase(testcase8v6, TestCase::Duration::QUICK);
 
     // 9. Test behavior of last reply lost in a count-limited configuration.
     // Limited pings, no losses, StopApplication () with no packet in flight
@@ -893,7 +893,7 @@
     testcase9v4->CheckReportReceived(2);
     testcase9v4->CheckReportLoss(33); // 33%
     testcase9v4->CheckReportTime(MicroSeconds(3040000));
-    AddTestCase(testcase9v4, TestCase::QUICK);
+    AddTestCase(testcase9v4, TestCase::Duration::QUICK);
 
     auto testcase9v6 = new PingTestCase(
         "9. Test behavior of last reply lost in a count-limited configuration, IPv6",
@@ -909,7 +909,7 @@
     testcase9v6->CheckReportReceived(2);
     testcase9v6->CheckReportLoss(33); // 33%
     testcase9v6->CheckReportTime(MicroSeconds(3040000));
-    AddTestCase(testcase9v6, TestCase::QUICK);
+    AddTestCase(testcase9v6, TestCase::Duration::QUICK);
 
 #ifdef NOTYET
     //
@@ -933,7 +933,7 @@
     testcase10v4->CheckReportTransmitted(1);
     testcase10v4->CheckReportReceived(1);
     testcase10v4->CheckReportTime(MicroSeconds(1020028));
-    AddTestCase(testcase10v4, TestCase::QUICK);
+    AddTestCase(testcase10v4, TestCase::Duration::QUICK);
 #endif
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-active-scan.cc ns-3.42/src/lr-wpan/examples/lr-wpan-active-scan.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-active-scan.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-active-scan.cc	2024-05-29 15:29:46.972073300 -0700
@@ -52,11 +52,12 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 static void
 ScanConfirm(Ptr<LrWpanNetDevice> device, MlmeScanConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         std::cout << Simulator::Now().As(Time::S) << "| Active scan status SUCCESSFUL (Completed)"
                   << "\n";
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-bootstrap.cc ns-3.42/src/lr-wpan/examples/lr-wpan-bootstrap.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-bootstrap.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-bootstrap.cc	2024-05-29 15:29:46.972073300 -0700
@@ -49,6 +49,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NodeContainer nodes;
 NodeContainer coordinators;
@@ -88,7 +89,7 @@
     // with the highest LQI value obtained from a passive scan and make
     // sure this coordinator allows association.
 
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         // Select the coordinator with the highest LQI from the PAN Descriptor List
         int maxLqi = 0;
@@ -137,16 +138,16 @@
                     CapabilityField capability;
 
                     if (params.m_panDescList[panDescIndex].m_coorAddrMode ==
-                        LrWpanAddressMode::SHORT_ADDR)
+                        AddressMode::SHORT_ADDR)
                     {
-                        assocParams.m_coordAddrMode = LrWpanAddressMode::SHORT_ADDR;
+                        assocParams.m_coordAddrMode = AddressMode::SHORT_ADDR;
                         assocParams.m_coordShortAddr =
                             params.m_panDescList[panDescIndex].m_coorShortAddr;
                         capability.SetShortAddrAllocOn(true);
                     }
-                    else if (assocParams.m_coordAddrMode == LrWpanAddressMode::EXT_ADDR)
+                    else if (assocParams.m_coordAddrMode == AddressMode::EXT_ADDR)
                     {
-                        assocParams.m_coordAddrMode = LrWpanAddressMode::EXT_ADDR;
+                        assocParams.m_coordAddrMode = AddressMode::EXT_ADDR;
                         assocParams.m_coordExtAddr =
                             params.m_panDescList[panDescIndex].m_coorExtAddr;
                         assocParams.m_coordShortAddr = Mac16Address("ff:fe");
@@ -209,7 +210,7 @@
     MlmeAssociateResponseParams assocRespParams;
 
     assocRespParams.m_extDevAddr = params.m_extDevAddr;
-    assocRespParams.m_status = LrWpanMacStatus::SUCCESS;
+    assocRespParams.m_status = MacStatus::SUCCESS;
     CapabilityField capability;
     capability.SetCapability(params.capabilityInfo);
 
@@ -248,14 +249,14 @@
     // and is only here for demonstration purposes.
     switch (params.m_status)
     {
-    case LrWpanMacStatus::TRANSACTION_EXPIRED:
+    case MacStatus::TRANSACTION_EXPIRED:
         std::cout << Simulator::Now().As(Time::S) << " Coordinator " << device->GetNode()->GetId()
                   << " [" << device->GetMac()->GetShortAddress() << " | "
                   << device->GetMac()->GetExtendedAddress() << "]"
                   << " MLME-comm-status.indication: Transaction for device " << params.m_dstExtAddr
                   << " EXPIRED in pending transaction list\n";
         break;
-    case LrWpanMacStatus::NO_ACK:
+    case MacStatus::NO_ACK:
         std::cout << Simulator::Now().As(Time::S) << " Coordinator " << device->GetNode()->GetId()
                   << " [" << device->GetMac()->GetShortAddress() << " | "
                   << device->GetMac()->GetExtendedAddress() << "]"
@@ -263,7 +264,7 @@
                   << " device registered in the pending transaction list\n";
         break;
 
-    case LrWpanMacStatus::CHANNEL_ACCESS_FAILURE:
+    case MacStatus::CHANNEL_ACCESS_FAILURE:
         std::cout << Simulator::Now().As(Time::S) << " Coordinator " << device->GetNode()->GetId()
                   << " [" << device->GetMac()->GetShortAddress() << " | "
                   << device->GetMac()->GetExtendedAddress() << "]"
@@ -282,7 +283,7 @@
     // Used by device higher layer to inform the results of a
     // association procedure from its mac layer.This is implemented by other protocol stacks
     // and is only here for demonstration purposes.
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
                   << device->GetMac()->GetShortAddress() << " | "
@@ -292,7 +293,7 @@
                   << " | CoordShort: " << device->GetMac()->GetCoordShortAddress()
                   << " | CoordExt: " << device->GetMac()->GetCoordExtAddress() << ")\n";
     }
-    else if (params.m_status == LrWpanMacStatus::NO_ACK)
+    else if (params.m_status == MacStatus::NO_ACK)
     {
         std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
                   << device->GetMac()->GetShortAddress() << " | "
@@ -311,7 +312,7 @@
 static void
 PollConfirm(Ptr<LrWpanNetDevice> device, MlmePollConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::CHANNEL_ACCESS_FAILURE)
+    if (params.m_status == MacStatus::CHANNEL_ACCESS_FAILURE)
     {
         std::cout
             << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
@@ -319,14 +320,14 @@
             << device->GetMac()->GetExtendedAddress() << "]"
             << " MLME-poll.confirm:  CHANNEL ACCESS problem when sending a data request command.\n";
     }
-    else if (params.m_status == LrWpanMacStatus::NO_ACK)
+    else if (params.m_status == MacStatus::NO_ACK)
     {
         std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
                   << device->GetMac()->GetShortAddress() << " | "
                   << device->GetMac()->GetExtendedAddress() << "]"
                   << " MLME-poll.confirm: Data Request Command FAILED (NO ACK).\n";
     }
-    else if (params.m_status != LrWpanMacStatus::SUCCESS)
+    else if (params.m_status != MacStatus::SUCCESS)
     {
         std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
                   << device->GetMac()->GetShortAddress() << " | "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-data.cc ns-3.42/src/lr-wpan/examples/lr-wpan-data.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-data.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-data.cc	2024-05-29 15:29:46.972073300 -0700
@@ -37,6 +37,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 /**
  * Function called when a Data indication is invoked
@@ -69,8 +70,8 @@
 static void
 StateChangeNotification(std::string context,
                         Time now,
-                        LrWpanPhyEnumeration oldState,
-                        LrWpanPhyEnumeration newState)
+                        PhyEnumeration oldState,
+                        PhyEnumeration newState)
 {
     NS_LOG_UNCOND(context << " state change at " << now.As(Time::S) << " from "
                           << LrWpanHelper::LrWpanPhyEnumerationPrinter(oldState) << " to "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-ed-scan.cc ns-3.42/src/lr-wpan/examples/lr-wpan-ed-scan.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-ed-scan.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-ed-scan.cc	2024-05-29 15:29:46.972073300 -0700
@@ -52,11 +52,12 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 static void
 ScanConfirm(MlmeScanConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS && params.m_scanType == MLMESCAN_ED)
+    if (params.m_status == MacStatus::SUCCESS && params.m_scanType == MLMESCAN_ED)
     {
         std::cout << Simulator::Now().As(Time::S) << "| Scan status SUCCESSFUL\n";
         std::cout << "Results for Energy Scan:"
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-error-distance-plot.cc ns-3.42/src/lr-wpan/examples/lr-wpan-error-distance-plot.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-error-distance-plot.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-error-distance-plot.cc	2024-05-29 15:29:46.972073300 -0700
@@ -65,6 +65,7 @@
 #include <vector>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 uint32_t g_packetsReceived = 0; //!< number of packets received
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-error-model-plot.cc ns-3.42/src/lr-wpan/examples/lr-wpan-error-model-plot.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-error-model-plot.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-error-model-plot.cc	2024-05-29 15:29:46.972073300 -0700
@@ -32,6 +32,7 @@
 #include <vector>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("LrWpanErrorModelPlot");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-mlme.cc ns-3.42/src/lr-wpan/examples/lr-wpan-mlme.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-mlme.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-mlme.cc	2024-05-29 15:29:46.972073300 -0700
@@ -45,6 +45,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 void
 BeaconIndication(MlmeBeaconNotifyIndicationParams params)
@@ -64,7 +65,7 @@
 {
     // In the case of transmissions with the Ack flag activated, the transaction is only
     // successful if the Ack was received.
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         NS_LOG_UNCOND(Simulator::Now().GetSeconds() << " secs | Transmission successfully sent");
     }
@@ -80,7 +81,7 @@
 void
 StartConfirm(MlmeStartConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         NS_LOG_UNCOND(Simulator::Now().GetSeconds() << "Beacon status SUCCESSFUL");
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-orphan-scan.cc ns-3.42/src/lr-wpan/examples/lr-wpan-orphan-scan.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-orphan-scan.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-orphan-scan.cc	2024-05-29 15:29:46.972073300 -0700
@@ -64,11 +64,12 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 static void
 ScanConfirm(Ptr<LrWpanNetDevice> device, MlmeScanConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
                   << device->GetMac()->GetShortAddress() << " | "
@@ -76,7 +77,7 @@
                   << "] MLME-SCAN.confirm: Active scan status SUCCESSFUL "
                   << "(Coordinator found and address assigned) \n";
     }
-    else if (params.m_status == LrWpanMacStatus::NO_BEACON)
+    else if (params.m_status == MacStatus::NO_BEACON)
     {
         std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " ["
                   << device->GetMac()->GetShortAddress() << " | "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-packet-print.cc ns-3.42/src/lr-wpan/examples/lr-wpan-packet-print.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-packet-print.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-packet-print.cc	2024-05-29 15:29:46.972073300 -0700
@@ -22,6 +22,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 int
 main(int argc, char* argv[])
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-per-plot.cc ns-3.42/src/lr-wpan/examples/lr-wpan-per-plot.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-per-plot.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-per-plot.cc	2024-05-29 15:29:46.976073300 -0700
@@ -43,6 +43,7 @@
 #include <ns3/spectrum-module.h>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 uint32_t g_packetsReceived = 0; //!< number of packets received
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/examples/lr-wpan-phy-test.cc ns-3.42/src/lr-wpan/examples/lr-wpan-phy-test.cc
--- ns-3.41/src/lr-wpan/examples/lr-wpan-phy-test.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/examples/lr-wpan-phy-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -27,13 +27,14 @@
 #include <ns3/test.h>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 /**
  * Function called when a the PHY state change is confirmed
  * \param status PHY state
  */
 void
-GetSetTRXStateConfirm(LrWpanPhyEnumeration status)
+GetSetTRXStateConfirm(PhyEnumeration status)
 {
     NS_LOG_UNCOND("At: " << Simulator::Now() << " Received Set TRX Confirm: " << status);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/helper/lr-wpan-helper.cc ns-3.42/src/lr-wpan/helper/lr-wpan-helper.cc
--- ns-3.41/src/lr-wpan/helper/lr-wpan-helper.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/helper/lr-wpan-helper.cc	2024-05-29 15:29:46.976073300 -0700
@@ -116,35 +116,35 @@
 }
 
 std::string
-LrWpanHelper::LrWpanPhyEnumerationPrinter(LrWpanPhyEnumeration e)
+LrWpanHelper::LrWpanPhyEnumerationPrinter(lrwpan::PhyEnumeration e)
 {
     switch (e)
     {
-    case IEEE_802_15_4_PHY_BUSY:
+    case lrwpan::IEEE_802_15_4_PHY_BUSY:
         return std::string("BUSY");
-    case IEEE_802_15_4_PHY_BUSY_RX:
+    case lrwpan::IEEE_802_15_4_PHY_BUSY_RX:
         return std::string("BUSY_RX");
-    case IEEE_802_15_4_PHY_BUSY_TX:
+    case lrwpan::IEEE_802_15_4_PHY_BUSY_TX:
         return std::string("BUSY_TX");
-    case IEEE_802_15_4_PHY_FORCE_TRX_OFF:
+    case lrwpan::IEEE_802_15_4_PHY_FORCE_TRX_OFF:
         return std::string("FORCE_TRX_OFF");
-    case IEEE_802_15_4_PHY_IDLE:
+    case lrwpan::IEEE_802_15_4_PHY_IDLE:
         return std::string("IDLE");
-    case IEEE_802_15_4_PHY_INVALID_PARAMETER:
+    case lrwpan::IEEE_802_15_4_PHY_INVALID_PARAMETER:
         return std::string("INVALID_PARAMETER");
-    case IEEE_802_15_4_PHY_RX_ON:
+    case lrwpan::IEEE_802_15_4_PHY_RX_ON:
         return std::string("RX_ON");
-    case IEEE_802_15_4_PHY_SUCCESS:
+    case lrwpan::IEEE_802_15_4_PHY_SUCCESS:
         return std::string("SUCCESS");
-    case IEEE_802_15_4_PHY_TRX_OFF:
+    case lrwpan::IEEE_802_15_4_PHY_TRX_OFF:
         return std::string("TRX_OFF");
-    case IEEE_802_15_4_PHY_TX_ON:
+    case lrwpan::IEEE_802_15_4_PHY_TX_ON:
         return std::string("TX_ON");
-    case IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE:
+    case lrwpan::IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE:
         return std::string("UNSUPPORTED_ATTRIBUTE");
-    case IEEE_802_15_4_PHY_READ_ONLY:
+    case lrwpan::IEEE_802_15_4_PHY_READ_ONLY:
         return std::string("READ_ONLY");
-    case IEEE_802_15_4_PHY_UNSPECIFIED:
+    case lrwpan::IEEE_802_15_4_PHY_UNSPECIFIED:
         return std::string("UNSPECIFIED");
     default:
         return std::string("INVALID");
@@ -152,17 +152,17 @@
 }
 
 std::string
-LrWpanHelper::LrWpanMacStatePrinter(LrWpanMacState e)
+LrWpanHelper::LrWpanMacStatePrinter(lrwpan::MacState e)
 {
     switch (e)
     {
-    case MAC_IDLE:
+    case lrwpan::MAC_IDLE:
         return std::string("MAC_IDLE");
-    case CHANNEL_ACCESS_FAILURE:
+    case lrwpan::CHANNEL_ACCESS_FAILURE:
         return std::string("CHANNEL_ACCESS_FAILURE");
-    case CHANNEL_IDLE:
+    case lrwpan::CHANNEL_IDLE:
         return std::string("CHANNEL_IDLE");
-    case SET_PHY_TX_ON:
+    case lrwpan::SET_PHY_TX_ON:
         return std::string("SET_PHY_TX_ON");
     default:
         return std::string("INVALID");
@@ -170,7 +170,7 @@
 }
 
 void
-LrWpanHelper::AddMobility(Ptr<LrWpanPhy> phy, Ptr<MobilityModel> m)
+LrWpanHelper::AddMobility(Ptr<lrwpan::LrWpanPhy> phy, Ptr<MobilityModel> m)
 {
     phy->SetMobility(m);
 }
@@ -183,7 +183,7 @@
     {
         Ptr<Node> node = *i;
 
-        Ptr<LrWpanNetDevice> netDevice = CreateObject<LrWpanNetDevice>();
+        Ptr<lrwpan::LrWpanNetDevice> netDevice = CreateObject<lrwpan::LrWpanNetDevice>();
         netDevice->SetChannel(m_channel);
         node->AddDevice(netDevice);
         netDevice->SetNode(node);
@@ -221,7 +221,7 @@
     for (auto i = c.Begin(); i != c.End(); ++i)
     {
         netDevice = (*i);
-        Ptr<LrWpanNetDevice> lrwpan = DynamicCast<LrWpanNetDevice>(netDevice);
+        Ptr<lrwpan::LrWpanNetDevice> lrwpan = DynamicCast<lrwpan::LrWpanNetDevice>(netDevice);
         if (lrwpan)
         {
             currentStream += lrwpan->AssignStreams(currentStream);
@@ -249,7 +249,7 @@
             NS_ABORT_MSG("Only 65533 addresses supported. Range [00:01]-[FF:FD]");
         }
 
-        Ptr<LrWpanNetDevice> device = DynamicCast<LrWpanNetDevice>(*i);
+        Ptr<lrwpan::LrWpanNetDevice> device = DynamicCast<lrwpan::LrWpanNetDevice>(*i);
         if (device)
         {
             idBuf[0] = (id >> 8) & 0xff;
@@ -287,7 +287,7 @@
 
     for (auto i = c.Begin(); i != c.End(); i++)
     {
-        Ptr<LrWpanNetDevice> device = DynamicCast<LrWpanNetDevice>(*i);
+        Ptr<lrwpan::LrWpanNetDevice> device = DynamicCast<lrwpan::LrWpanNetDevice>(*i);
         if (device)
         {
             idBuf[0] = (id >> 56) & 0xff;
@@ -338,7 +338,7 @@
     // have to switch on each type below and insert into the right
     // NetDevice type
     //
-    Ptr<LrWpanNetDevice> device = nd->GetObject<LrWpanNetDevice>();
+    Ptr<lrwpan::LrWpanNetDevice> device = nd->GetObject<lrwpan::LrWpanNetDevice>();
     if (!device)
     {
         NS_LOG_INFO("LrWpanHelper::EnablePcapInternal(): Device "
@@ -383,7 +383,7 @@
     uint32_t deviceid = nd->GetIfIndex();
     std::ostringstream oss;
 
-    Ptr<LrWpanNetDevice> device = nd->GetObject<LrWpanNetDevice>();
+    Ptr<lrwpan::LrWpanNetDevice> device = nd->GetObject<lrwpan::LrWpanNetDevice>();
     if (!device)
     {
         NS_LOG_INFO("LrWpanHelper::EnableAsciiInternal(): Device "
@@ -428,23 +428,23 @@
         // The Mac and Phy objects have the trace sources for these
         //
 
-        asciiTraceHelper.HookDefaultReceiveSinkWithoutContext<LrWpanMac>(device->GetMac(),
-                                                                         "MacRx",
-                                                                         theStream);
+        asciiTraceHelper.HookDefaultReceiveSinkWithoutContext<lrwpan::LrWpanMac>(device->GetMac(),
+                                                                                 "MacRx",
+                                                                                 theStream);
 
         device->GetMac()->TraceConnectWithoutContext(
             "MacTx",
             MakeBoundCallback(&AsciiLrWpanMacTransmitSinkWithoutContext, theStream));
 
-        asciiTraceHelper.HookDefaultEnqueueSinkWithoutContext<LrWpanMac>(device->GetMac(),
-                                                                         "MacTxEnqueue",
-                                                                         theStream);
-        asciiTraceHelper.HookDefaultDequeueSinkWithoutContext<LrWpanMac>(device->GetMac(),
-                                                                         "MacTxDequeue",
-                                                                         theStream);
-        asciiTraceHelper.HookDefaultDropSinkWithoutContext<LrWpanMac>(device->GetMac(),
-                                                                      "MacTxDrop",
-                                                                      theStream);
+        asciiTraceHelper.HookDefaultEnqueueSinkWithoutContext<lrwpan::LrWpanMac>(device->GetMac(),
+                                                                                 "MacTxEnqueue",
+                                                                                 theStream);
+        asciiTraceHelper.HookDefaultDequeueSinkWithoutContext<lrwpan::LrWpanMac>(device->GetMac(),
+                                                                                 "MacTxDequeue",
+                                                                                 theStream);
+        asciiTraceHelper.HookDefaultDropSinkWithoutContext<lrwpan::LrWpanMac>(device->GetMac(),
+                                                                              "MacTxDrop",
+                                                                              theStream);
 
         return;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/helper/lr-wpan-helper.h ns-3.42/src/lr-wpan/helper/lr-wpan-helper.h
--- ns-3.41/src/lr-wpan/helper/lr-wpan-helper.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/helper/lr-wpan-helper.h	2024-05-29 15:29:46.976073300 -0700
@@ -99,7 +99,7 @@
      * \param phy the physical device
      * \param m the mobility model
      */
-    void AddMobility(Ptr<LrWpanPhy> phy, Ptr<MobilityModel> m);
+    void AddMobility(Ptr<lrwpan::LrWpanPhy> phy, Ptr<MobilityModel> m);
 
     /**
      * \brief Install a LrWpanNetDevice and the associated structures (e.g., channel) in the nodes.
@@ -137,14 +137,14 @@
      * \param e the LrWpanPhyEnumeration
      * \return a string
      */
-    static std::string LrWpanPhyEnumerationPrinter(LrWpanPhyEnumeration e);
+    static std::string LrWpanPhyEnumerationPrinter(lrwpan::PhyEnumeration e);
 
     /**
      * \brief Transform the LrWpanMacState enumeration into a printable string.
      * \param e the LrWpanMacState
      * \return a string
      */
-    static std::string LrWpanMacStatePrinter(LrWpanMacState e);
+    static std::string LrWpanMacStatePrinter(lrwpan::MacState e);
 
     /**
      * Assign a fixed random variable stream number to the random variables
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-constants.h ns-3.42/src/lr-wpan/model/lr-wpan-constants.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-constants.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-constants.h	2024-05-29 15:29:46.976073300 -0700
@@ -34,7 +34,7 @@
 {
 
 /**
- * \defgroup LrWpanConstants
+ * \defgroup LrWpanConstants LR-WPAN common parameters
  * \ingroup lr-wpan
  *
  * Contains common parameters about LR-WPAN that can be reused in multiple files.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-csmaca.cc ns-3.42/src/lr-wpan/model/lr-wpan-csmaca.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-csmaca.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-csmaca.cc	2024-05-29 15:29:46.976073300 -0700
@@ -37,9 +37,10 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanCsmaCa");
-
 NS_OBJECT_ENSURE_REGISTERED(LrWpanCsmaCa);
 
 TypeId
@@ -78,7 +79,7 @@
 void
 LrWpanCsmaCa::DoDispose()
 {
-    m_lrWpanMacStateCallback = MakeNullCallback<void, LrWpanMacState>();
+    m_lrWpanMacStateCallback = MakeNullCallback<void, MacState>();
     m_lrWpanMacTransCostCallback = MakeNullCallback<void, uint32_t>();
 
     Cancel();
@@ -253,7 +254,7 @@
         }
 
         // m_coorDest to decide between incoming and outgoing superframes times
-        m_coorDest = m_mac->isCoordDest();
+        m_coorDest = m_mac->IsCoordDest();
 
         // Locate backoff period boundary. (i.e. a time delay to align with the next backoff period
         // boundary)
@@ -405,7 +406,7 @@
 
     transactionSymbols = ccaSymbols + m_mac->GetTxPacketSymbols();
 
-    if (m_mac->isTxAckReq())
+    if (m_mac->IsTxAckReq())
     {
         NS_LOG_DEBUG("ACK duration symbols: " << m_mac->GetMacAckWaitDuration());
         transactionSymbols += m_mac->GetMacAckWaitDuration();
@@ -460,7 +461,7 @@
 }
 
 void
-LrWpanCsmaCa::PlmeCcaConfirm(LrWpanPhyEnumeration status)
+LrWpanCsmaCa::PlmeCcaConfirm(PhyEnumeration status)
 {
     NS_LOG_FUNCTION(this << status);
 
@@ -571,4 +572,5 @@
     return m_macBattLifeExt;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-csmaca.h ns-3.42/src/lr-wpan/model/lr-wpan-csmaca.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-csmaca.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-csmaca.h	2024-05-29 15:29:46.976073300 -0700
@@ -33,12 +33,15 @@
 
 class UniformRandomVariable;
 
+namespace lrwpan
+{
+
 /**
  * \ingroup lr-wpan
  *
  * This method informs the MAC whether the channel is idle or busy.
  */
-typedef Callback<void, LrWpanMacState> LrWpanMacStateCallback;
+typedef Callback<void, MacState> LrWpanMacStateCallback;
 /**
  * \ingroup lr-wpan
  *
@@ -198,7 +201,7 @@
      * permitting transmission (step 5). If channel is busy, either backoff and perform CCA again or
      * treat as channel access failure (step 4).
      */
-    void PlmeCcaConfirm(LrWpanPhyEnumeration status);
+    void PlmeCcaConfirm(PhyEnumeration status);
     /**
      * Set the callback function to report a transaction cost in slotted CSMA-CA. The callback is
      * triggered in CanProceed() after calculating the transaction cost (2 CCA checks,transmission
@@ -331,6 +334,7 @@
     bool m_coorDest;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 // namespace ns-3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-error-model.cc ns-3.42/src/lr-wpan/model/lr-wpan-error-model.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-error-model.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-error-model.cc	2024-05-29 15:29:46.976073300 -0700
@@ -24,9 +24,10 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanErrorModel");
-
 NS_OBJECT_ENSURE_REGISTERED(LrWpanErrorModel);
 
 TypeId
@@ -76,5 +77,5 @@
     double retval = pow(1.0 - ber, nbits);
     return retval;
 }
-
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-error-model.h ns-3.42/src/lr-wpan/model/lr-wpan-error-model.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-error-model.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-error-model.h	2024-05-29 15:29:46.976073300 -0700
@@ -23,6 +23,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /**
  * \ingroup lr-wpan
@@ -58,7 +60,7 @@
      */
     double m_binomialCoefficients[17];
 };
-
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_ERROR_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-fields.cc ns-3.42/src/lr-wpan/model/lr-wpan-fields.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-fields.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-fields.cc	2024-05-29 15:29:46.976073300 -0700
@@ -24,6 +24,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 SuperframeField::SuperframeField()
 {
@@ -587,4 +589,5 @@
     return os;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-fields.h ns-3.42/src/lr-wpan/model/lr-wpan-fields.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-fields.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-fields.h	2024-05-29 15:29:46.976073300 -0700
@@ -34,6 +34,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /**
  * \ingroup lr-wpan
@@ -458,6 +460,7 @@
 
 std::ostream& operator<<(std::ostream& os, const CapabilityField& capabilityField);
 
-} // end namespace ns3
+} // namespace lrwpan
+} // namespace ns3
 
 #endif /* LR_WPAN_FIELDS_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-interference-helper.cc ns-3.42/src/lr-wpan/model/lr-wpan-interference-helper.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-interference-helper.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-interference-helper.cc	2024-05-29 15:29:46.976073300 -0700
@@ -25,6 +25,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanInterferenceHelper");
 
@@ -106,4 +108,5 @@
     return m_signal->Copy();
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-interference-helper.h ns-3.42/src/lr-wpan/model/lr-wpan-interference-helper.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-interference-helper.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-interference-helper.h	2024-05-29 15:29:46.976073300 -0700
@@ -31,6 +31,9 @@
 class SpectrumValue;
 class SpectrumModel;
 
+namespace lrwpan
+{
+
 /**
  * \ingroup lr-wpan
  *
@@ -120,6 +123,7 @@
     mutable bool m_dirty;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_INTERFERENCE_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-lqi-tag.cc ns-3.42/src/lr-wpan/model/lr-wpan-lqi-tag.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-lqi-tag.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-lqi-tag.cc	2024-05-29 15:29:46.976073300 -0700
@@ -23,6 +23,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_OBJECT_ENSURE_REGISTERED(LrWpanLqiTag);
 
@@ -93,4 +95,5 @@
     return m_lqi;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-lqi-tag.h ns-3.42/src/lr-wpan/model/lr-wpan-lqi-tag.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-lqi-tag.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-lqi-tag.h	2024-05-29 15:29:46.976073300 -0700
@@ -24,6 +24,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /**
  * \ingroup lr-wpan
@@ -83,5 +85,6 @@
     uint8_t m_lqi;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 #endif /* LR_WPAN_LQI_TAG_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-base.cc ns-3.42/src/lr-wpan/model/lr-wpan-mac-base.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-base.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-base.cc	2024-05-29 15:29:46.976073300 -0700
@@ -24,6 +24,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanMacBase");
 NS_OBJECT_ENSURE_REGISTERED(LrWpanMacBase);
@@ -117,4 +119,5 @@
     m_mlmePollConfirmCallback = c;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-base.h ns-3.42/src/lr-wpan/model/lr-wpan-mac-base.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-base.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-base.h	2024-05-29 15:29:46.976073300 -0700
@@ -32,6 +32,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /**
  * \ingroup lr-wpan
@@ -45,7 +47,7 @@
  * (Table 6: Status Enumerations and Section 6.1.23)
  *
  */
-enum class LrWpanMacStatus : std::uint8_t
+enum class MacStatus : std::uint8_t
 {
     SUCCESS = 0,              //!< The operation was completed successfully.
     FULL_CAPACITY = 0x01,     //!< PAN at capacity. Association Status field (std. 2006, Table 83)
@@ -84,7 +86,7 @@
     LIMIT_REACHED = 0xfa,     //!< PAN descriptors stored reached max capacity.
     READ_ONLY = 0xfb,         //!< SET/GET request issued for a read only attribute.
     SCAN_IN_PROGRESS = 0xfc,  //!< Scan failed because already performing another scan.
-    SUPERFRAME_OVERLAP = 0xfd //!< Coordinator sperframe and this device superframe tx overlap.
+    SUPERFRAME_OVERLAP = 0xfd //!< Coordinator superframe and this device superframe tx overlap.
 };
 
 /**
@@ -92,7 +94,7 @@
  *
  * table 80 of 802.15.4
  */
-enum LrWpanAddressMode
+enum AddressMode
 {
     NO_PANID_ADDR = 0,
     ADDR_MODE_RESERVED = 1,
@@ -105,7 +107,7 @@
  *
  * Table 30 of IEEE 802.15.4-2011
  */
-enum LrWpanMlmeScanType
+enum MlmeScanType
 {
     MLMESCAN_ED = 0x00,
     MLMESCAN_ACTIVE = 0x01,
@@ -120,13 +122,13 @@
  */
 struct McpsDataRequestParams
 {
-    LrWpanAddressMode m_srcAddrMode{SHORT_ADDR}; //!< Source address mode
-    LrWpanAddressMode m_dstAddrMode{SHORT_ADDR}; //!< Destination address mode
-    uint16_t m_dstPanId{0};                      //!< Destination PAN identifier
-    Mac16Address m_dstAddr;                      //!< Destination address
-    Mac64Address m_dstExtAddr;                   //!< Destination extended address
-    uint8_t m_msduHandle{0};                     //!< MSDU handle
-    uint8_t m_txOptions{0};                      //!< Tx Options (bitfield)
+    AddressMode m_srcAddrMode{SHORT_ADDR}; //!< Source address mode
+    AddressMode m_dstAddrMode{SHORT_ADDR}; //!< Destination address mode
+    uint16_t m_dstPanId{0};                //!< Destination PAN identifier
+    Mac16Address m_dstAddr;                //!< Destination address
+    Mac64Address m_dstExtAddr;             //!< Destination extended address
+    uint8_t m_msduHandle{0};               //!< MSDU handle
+    uint8_t m_txOptions{0};                //!< Tx Options (bitfield)
 };
 
 /**
@@ -160,11 +162,11 @@
  */
 struct MlmeScanRequestParams
 {
-    LrWpanMlmeScanType m_scanType{MLMESCAN_PASSIVE}; //!< Indicates the type of scan performed as
-                                                     //!< described in IEEE 802.15.4-2011 (5.1.2.1).
-    uint32_t m_scanChannels{0x7FFF800};              //!< The channel numbers to be scanned.
-                                                     //!< Default: (0x7FFF800 = Ch11-Ch26)
-                                                     //!< 27 LSB (b0,b1,...,b26) = channels
+    MlmeScanType m_scanType{MLMESCAN_PASSIVE}; //!< Indicates the type of scan performed as
+                                               //!< described in IEEE 802.15.4-2011 (5.1.2.1).
+    uint32_t m_scanChannels{0x7FFF800};        //!< The channel numbers to be scanned.
+                                               //!< Default: (0x7FFF800 = Ch11-Ch26)
+                                               //!< 27 LSB (b0,b1,...,b26) = channels
     uint8_t m_scanDuration{14}; //!< The factor (0-14) used to calculate the length of time
                                 //!< to spend scanning.
                                 //!< scanDurationSymbols =
@@ -202,9 +204,9 @@
     Mac64Address m_extDevAddr;     //!< The extended address of the device requesting association
     Mac16Address m_assocShortAddr; //!< The short address allocated by the coordinator on successful
                                    //!< assoc. FF:FF = Unsuccessful
-    LrWpanMacStatus m_status{
-        LrWpanMacStatus::ACCESS_DENIED}; //!< The status of the association
-                                         //!< attempt (As defined on Table 83 IEEE 802.15.4-2006)
+    MacStatus m_status{
+        MacStatus::ACCESS_DENIED}; //!< The status of the association
+                                   //!< attempt (As defined on Table 83 IEEE 802.15.4-2006)
 };
 
 /**
@@ -238,8 +240,8 @@
  */
 struct MlmePollRequestParams
 {
-    LrWpanAddressMode m_coorAddrMode{SHORT_ADDR}; //!< The addressing mode of the coordinator
-                                                  //!< to which the pool is intended.
+    AddressMode m_coorAddrMode{SHORT_ADDR}; //!< The addressing mode of the coordinator
+                                            //!< to which the pool is intended.
     uint16_t m_coorPanId{0};      //!< The PAN id of the coordinator to which the poll is intended.
     Mac16Address m_coorShortAddr; //!< Coordinator short address.
     Mac64Address m_coorExtAddr;   //!< Coordinator extended address.
@@ -248,18 +250,56 @@
 /**
  * \ingroup lr-wpan
  *
- * IEEE802.15.4-2011 MAC PIB Attribute Identifiers Table 52 in section 6.4.2
- *
+ * IEEE 802.15.4-2006 PHY and MAC PIB Attribute Identifiers Table 23 and Table 86.
+ * Note: Attribute identifiers use standardized values.
  */
-enum LrWpanMacPibAttributeIdentifier
+enum MacPibAttributeIdentifier
 {
-    macBeaconPayload = 0,
-    macBeaconPayloadLength = 1,
-    macShortAddress = 2,
-    macExtendedAddress = 3,
-    macPanId = 4,
-    pCurrentChannel = 100,
-    pCurrentPage = 101,
+    pCurrentChannel = 0x00,      //!< RF channel used for transmissions and receptions.
+    pCurrentPage = 0x04,         //!< The current channel page.
+    macAckWaitDuration = 0x40,   //!< Maximum number of symbols to wait for an acknowledgment.
+    macAssociationPermit = 0x41, //!< Indication of whether a coordinator is allowing association.
+    macAutoRequest = 0x42, //!< Indication of whether a device automatically sends a data request
+                           //!< command if its address is listed in a beacon frame.
+    macBattLifeExt = 0x43, //!< Indication of whether BLE, through the reduction of coordinator
+                           //!< receiver operation time during the CAP, is enabled.
+    macBattLifeExtPeriods = 0x44,  //!< In BLE mode, the number of backoff periods during which the
+                                   //!< the receiver is enabled after the IFS following a beacon.
+    macBeaconPayload = 0x45,       //!< The contents of the beacon payload.
+    macBeaconPayloadLength = 0x46, //!< The length in octets of the beacon payload.
+    macBeaconOrder = 0x47,  //!< Specification of how often the coordinator transmits its beacon.
+    macBeaconTxTime = 0x48, //!< The time that the device transmitted its last beacome frame,
+                            //!< in symbol periods.
+    macBsn = 0x49,          //!< The sequence number added to the transmitted beacon frame.
+    macCoordExtendedAddress = 0x4a, //!< The 64-bit address of the coordinator through which
+                                    //!< the device is associated.
+    macCoordShortAddress = 0x4b, //!< The 16-bit short address assigned to the coordinator through
+                                 //!< which the device is associated. 0xFFFE = Ext address mode
+                                 //!< 0xFFFF = Unknown.
+    macDSN = 0x4c, //!< The sequence number added to the transmitted data or MAC command frame.
+    macGTSPermit = 0x4d,      //!< True if the PAN coordinator is to accept GTS requests.
+    macMaxCSMABackoff = 0x4e, //!< The maximum number of backoffs the CSMA-CA algorithm
+                              //!< will attempt before declaring a channel access failure.
+    macMinBE = 0x4f, //!< The minimum value of the backoff exponent (BE) in the CSMA-CA algorithm.
+    macExtendedAddress = 0x6f, //!< The extended address of the device (64 bit address). The id
+                               //!< is not compliant for 2003 and 2006 versions, but this attribute
+                               //!< is later on added to the Pib attributes in 2011 and subsequent
+                               //!< editions of the standard.
+    macPanId = 0x50,           //!< The 16-bit identifier of the Personal Area Network (PAN).
+    macPromiscuousMode = 0x51, //!< Indication of whether the MAC sublayer is in a promiscuous
+                               //!< mode. True indicates that the MAC sublayer accepts all frames.
+    macRxOnWhenIdle = 0x52,    //!< Indication of whether the MAC is enabled during idle periods.
+    macShortAddress = 0x53,    //!< The short address of the device (16 bit address).
+    macSuperframeOrder = 0x54, //!< The length of the active portion of the outgoing superframe,
+                               //!< including the beacon frame.
+    macTransactionPersistenceTime = 0x55, //!< The maximum time (in unit periods) that a
+                                          //!< transaction is stored by a coordinator and
+                                          //!< indicated in its beacon.
+    macMaxFrameRetries = 0x59,  //!< The maximum number of retries allowed after a transmission
+                                //!< failure.
+    macResponseWaitTime = 0x5a, //!< The maximum time in multiples of aBaseSuperframeDuration, a
+                                //!< device shall wait for a response command frame to be
+                                //!< available following a request command frame.
     unsupported = 255
     // TODO: complete other MAC pib attributes
 };
@@ -269,7 +309,7 @@
  *
  * IEEE802.15.4-2011 PHY PIB Attributes Table 52 in section 6.4.2
  */
-struct LrWpanMacPibAttributes : public SimpleRefCount<LrWpanMacPibAttributes>
+struct MacPibAttributes : public SimpleRefCount<MacPibAttributes>
 {
     Ptr<Packet> macBeaconPayload;      //!< The contents of the beacon payload.
     uint8_t macBeaconPayloadLength{0}; //!< The length in octets of the beacon payload.
@@ -288,9 +328,9 @@
  */
 struct McpsDataConfirmParams
 {
-    uint8_t m_msduHandle{0};                                      //!< MSDU handle
-    LrWpanMacStatus m_status{LrWpanMacStatus::INVALID_PARAMETER}; //!< The status
-                                                                  //!< of the last MSDU transmission
+    uint8_t m_msduHandle{0};                          //!< MSDU handle
+    MacStatus m_status{MacStatus::INVALID_PARAMETER}; //!< The status
+                                                      //!< of the last MSDU transmission
 };
 
 /**
@@ -345,7 +385,7 @@
                                        //!< which the frame was intended.
     Mac64Address m_dstExtAddr;         //!< The extended address of the device for
                                        //!< which the frame was intended.
-    LrWpanMacStatus m_status{LrWpanMacStatus::INVALID_PARAMETER}; //!< The communication status
+    MacStatus m_status{MacStatus::INVALID_PARAMETER}; //!< The communication status
 };
 
 /**
@@ -365,8 +405,8 @@
  */
 struct MlmeStartConfirmParams
 {
-    LrWpanMacStatus m_status{LrWpanMacStatus::INVALID_PARAMETER}; //!< The status of
-                                                                  //!< a MLME-start.request
+    MacStatus m_status{MacStatus::INVALID_PARAMETER}; //!< The status of
+                                                      //!< a MLME-start.request
 };
 
 /**
@@ -376,10 +416,10 @@
  */
 struct PanDescriptor
 {
-    LrWpanAddressMode m_coorAddrMode{SHORT_ADDR}; //!< The coordinator addressing mode corresponding
-                                                  //!< to the received beacon frame.
-    uint16_t m_coorPanId{0xffff};                 //!< The PAN ID of the coordinator as specified in
-                                                  //!<  the received beacon frame.
+    AddressMode m_coorAddrMode{SHORT_ADDR}; //!< The coordinator addressing mode corresponding
+                                            //!< to the received beacon frame.
+    uint16_t m_coorPanId{0xffff};           //!< The PAN ID of the coordinator as specified in
+                                            //!<  the received beacon frame.
     Mac16Address m_coorShortAddr; //!< The coordinator short address as specified in the coordinator
                                   //!< address mode.
     Mac64Address m_coorExtAddr;   //!< The coordinator extended address as specified in the
@@ -403,18 +443,17 @@
  */
 struct MlmeScanConfirmParams
 {
-    LrWpanMacStatus m_status{
-        LrWpanMacStatus::INVALID_PARAMETER}; //!< The status of the scan request.
-    uint8_t m_scanType{MLMESCAN_PASSIVE};    //!< Indicates the type of scan
-                                             //!<  performed (ED,ACTIVE,PASSIVE,ORPHAN).
-    uint32_t m_chPage{0};                    //!< The channel page on which the scan was performed.
-    std::vector<uint8_t> m_unscannedCh;      //!< A list of channels given in the request which
-                                             //!<  were not scanned (Not valid for ED scans).
-    uint8_t m_resultListSize{0};             //!< The number of elements returned in the appropriate
-                                             //!<  result list. (Not valid for Orphan scan).
-    std::vector<uint8_t> m_energyDetList;    //!< A list of energy measurements, one for each
-                                             //!< channel searched during ED scan
-                                             //!< (Not valid for Active, Passive or Orphan Scans)
+    MacStatus m_status{MacStatus::INVALID_PARAMETER}; //!< The status of the scan request.
+    uint8_t m_scanType{MLMESCAN_PASSIVE};             //!< Indicates the type of scan
+                                                      //!<  performed (ED,ACTIVE,PASSIVE,ORPHAN).
+    uint32_t m_chPage{0};                 //!< The channel page on which the scan was performed.
+    std::vector<uint8_t> m_unscannedCh;   //!< A list of channels given in the request which
+                                          //!<  were not scanned (Not valid for ED scans).
+    uint8_t m_resultListSize{0};          //!< The number of elements returned in the appropriate
+                                          //!<  result list. (Not valid for Orphan scan).
+    std::vector<uint8_t> m_energyDetList; //!< A list of energy measurements, one for each
+                                          //!< channel searched during ED scan
+                                          //!< (Not valid for Active, Passive or Orphan Scans)
     std::vector<PanDescriptor> m_panDescList; //!< A list of PAN descriptor, one for each beacon
                                               //!< found (Not valid for ED and Orphan scans).
 };
@@ -427,8 +466,8 @@
 struct MlmeAssociateConfirmParams
 {
     Mac16Address m_assocShortAddr; //!< The short address used in the association request
-    LrWpanMacStatus m_status{LrWpanMacStatus::INVALID_PARAMETER}; //!< The status of
-                                                                  //!< a MLME-associate.request
+    MacStatus m_status{MacStatus::INVALID_PARAMETER}; //!< The status of
+                                                      //!< a MLME-associate.request
 };
 
 /**
@@ -451,8 +490,8 @@
  */
 struct MlmeSyncLossIndicationParams
 {
-    LrWpanMacStatus m_lossReason{LrWpanMacStatus::PAN_ID_CONFLICT}; //!< The reason for the lost
-                                                                    //!< of synchronization.
+    MacStatus m_lossReason{MacStatus::PAN_ID_CONFLICT}; //!< The reason for the lost
+                                                        //!< of synchronization.
     uint16_t m_panId{0}; //!< The PAN identifier with which the device lost synchronization or to
                          //!< which it was realigned.
     uint8_t m_logCh{11}; //!< The channel number on which the device lost synchronization or to
@@ -466,10 +505,10 @@
  */
 struct MlmeSetConfirmParams
 {
-    LrWpanMacStatus m_status{LrWpanMacStatus::UNSUPPORTED_ATTRIBUTE}; //!< The result of
-                                                                      //!< the request to write
-                                                                      //!< the PIB attribute.
-    LrWpanMacPibAttributeIdentifier id; //!< The id of the PIB attribute that was written.
+    MacStatus m_status{MacStatus::UNSUPPORTED_ATTRIBUTE}; //!< The result of
+                                                          //!< the request to write
+                                                          //!< the PIB attribute.
+    MacPibAttributeIdentifier id; //!< The id of the PIB attribute that was written.
 };
 
 /**
@@ -479,9 +518,9 @@
  */
 struct MlmePollConfirmParams
 {
-    LrWpanMacStatus m_status{LrWpanMacStatus::INVALID_PARAMETER}; //!< The confirmation
-                                                                  //!< status resulting from a
-                                                                  //!< MLME-poll.request.
+    MacStatus m_status{MacStatus::INVALID_PARAMETER}; //!< The confirmation
+                                                      //!< status resulting from a
+                                                      //!< MLME-poll.request.
 };
 
 /**
@@ -602,7 +641,7 @@
  * write attempt.
  */
 using MlmeGetConfirmCallback =
-    Callback<void, LrWpanMacStatus, LrWpanMacPibAttributeIdentifier, Ptr<LrWpanMacPibAttributes>>;
+    Callback<void, MacStatus, MacPibAttributeIdentifier, Ptr<MacPibAttributes>>;
 
 /**
  * \ingroup lr-wpan
@@ -719,17 +758,18 @@
      * \param id the attributed identifier
      * \param attribute the attribute value
      */
-    virtual void MlmeSetRequest(LrWpanMacPibAttributeIdentifier id,
-                                Ptr<LrWpanMacPibAttributes> attribute) = 0;
+    virtual void MlmeSetRequest(MacPibAttributeIdentifier id, Ptr<MacPibAttributes> attribute) = 0;
 
     /**
-     * IEEE 802.15.4-2011, section 6.2.5.1
+     * IEEE 802.15.4-2006, section 7.1.6.1
      * MLME-GET.request
      * Request information about a given PIB attribute.
+     * Note: The PibAttributeIndex parameter is not included because
+     * attributes that represent tables are not supported.
      *
      * \param id the attribute identifier
      */
-    virtual void MlmeGetRequest(LrWpanMacPibAttributeIdentifier id) = 0;
+    virtual void MlmeGetRequest(MacPibAttributeIdentifier id) = 0;
 
     /**
      * Set the callback for the confirmation of a data transmission request.
@@ -935,6 +975,7 @@
     MlmePollConfirmCallback m_mlmePollConfirmCallback;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_MAC_BASE_H*/
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac.cc ns-3.42/src/lr-wpan/model/lr-wpan-mac.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac.cc	2024-05-29 15:29:46.976073300 -0700
@@ -40,47 +40,49 @@
 
 #undef NS_LOG_APPEND_CONTEXT
 #define NS_LOG_APPEND_CONTEXT                                                                      \
-    std::clog << "[address " << m_shortAddress << " | " << m_selfExt << "] ";
+    std::clog << "[address " << m_shortAddress << " | " << m_macExtendedAddress << "] ";
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanMac");
 NS_OBJECT_ENSURE_REGISTERED(LrWpanMac);
 
 std::ostream&
-operator<<(std::ostream& os, const LrWpanMacState& state)
+operator<<(std::ostream& os, const MacState& state)
 {
     switch (state)
     {
-    case LrWpanMacState::MAC_IDLE:
+    case MacState::MAC_IDLE:
         os << "MAC IDLE";
         break;
-    case LrWpanMacState::MAC_CSMA:
+    case MacState::MAC_CSMA:
         os << "CSMA";
         break;
-    case LrWpanMacState::MAC_SENDING:
+    case MacState::MAC_SENDING:
         os << "SENDING";
         break;
-    case LrWpanMacState::MAC_ACK_PENDING:
+    case MacState::MAC_ACK_PENDING:
         os << "ACK PENDING";
         break;
-    case LrWpanMacState::CHANNEL_ACCESS_FAILURE:
+    case MacState::CHANNEL_ACCESS_FAILURE:
         os << "CHANNEL_ACCESS_FAILURE";
         break;
-    case LrWpanMacState::CHANNEL_IDLE:
+    case MacState::CHANNEL_IDLE:
         os << "CHANNEL IDLE";
         break;
-    case LrWpanMacState::SET_PHY_TX_ON:
+    case MacState::SET_PHY_TX_ON:
         os << "SET PHY to TX ON";
         break;
-    case LrWpanMacState::MAC_GTS:
+    case MacState::MAC_GTS:
         os << "MAC GTS PERIOD";
         break;
-    case LrWpanMacState::MAC_INACTIVE:
+    case MacState::MAC_INACTIVE:
         os << "SUPERFRAME INACTIVE PERIOD";
         break;
-    case LrWpanMacState::MAC_CSMA_DEFERRED:
+    case MacState::MAC_CSMA_DEFERRED:
         os << "CSMA DEFERRED TO NEXT PERIOD";
         break;
     }
@@ -172,7 +174,7 @@
                             "ns3::Packet::TracedCallback")
             .AddTraceSource("MacStateValue",
                             "The state of LrWpan Mac",
-                            MakeTraceSourceAccessor(&LrWpanMac::m_lrWpanMacState),
+                            MakeTraceSourceAccessor(&LrWpanMac::m_macState),
                             "ns3::TracedValueCallback::LrWpanMacState")
             .AddTraceSource("MacIncSuperframeStatus",
                             "The period status of the incoming superframe",
@@ -202,7 +204,7 @@
 LrWpanMac::LrWpanMac()
 {
     // First set the state to a known value, call ChangeMacState to fire trace source.
-    m_lrWpanMacState = MAC_IDLE;
+    m_macState = MAC_IDLE;
 
     ChangeMacState(MAC_IDLE);
 
@@ -214,7 +216,7 @@
     m_macCoordShortAddress = Mac16Address("ff:ff");
     m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
     m_deviceCapability = DeviceType::FFD;
-    m_selfExt = Mac64Address::Allocate();
+    m_macExtendedAddress = Mac64Address::Allocate();
     m_macPromiscuousMode = false;
     m_macMaxFrameRetries = 3;
     m_retransmission = 0;
@@ -339,7 +341,7 @@
     NS_LOG_FUNCTION(this << rxOnWhenIdle);
     m_macRxOnWhenIdle = rxOnWhenIdle;
 
-    if (m_lrWpanMacState == MAC_IDLE)
+    if (m_macState == MAC_IDLE)
     {
         if (m_macRxOnWhenIdle)
         {
@@ -363,7 +365,7 @@
 LrWpanMac::SetExtendedAddress(Mac64Address address)
 {
     NS_LOG_FUNCTION(this << address);
-    m_selfExt = address;
+    m_macExtendedAddress = address;
 }
 
 Mac16Address
@@ -377,7 +379,7 @@
 LrWpanMac::GetExtendedAddress() const
 {
     NS_LOG_FUNCTION(this);
-    return m_selfExt;
+    return m_macExtendedAddress;
 }
 
 void
@@ -402,7 +404,7 @@
         // The frame could still be too large once headers are put on
         // in which case the phy will reject it instead
         NS_LOG_ERROR(this << " packet too big: " << p->GetSize());
-        confirmParams.m_status = LrWpanMacStatus::FRAME_TOO_LONG;
+        confirmParams.m_status = MacStatus::FRAME_TOO_LONG;
         if (!m_mcpsDataConfirmCallback.IsNull())
         {
             m_mcpsDataConfirmCallback(confirmParams);
@@ -413,7 +415,7 @@
     if ((params.m_srcAddrMode == NO_PANID_ADDR) && (params.m_dstAddrMode == NO_PANID_ADDR))
     {
         NS_LOG_ERROR(this << " Can not send packet with no Address field");
-        confirmParams.m_status = LrWpanMacStatus::INVALID_ADDRESS;
+        confirmParams.m_status = MacStatus::INVALID_ADDRESS;
         if (!m_mcpsDataConfirmCallback.IsNull())
         {
             m_mcpsDataConfirmCallback(confirmParams);
@@ -440,7 +442,7 @@
     default:
         NS_LOG_ERROR(this << " Can not send packet with incorrect Source Address mode = "
                           << params.m_srcAddrMode);
-        confirmParams.m_status = LrWpanMacStatus::INVALID_ADDRESS;
+        confirmParams.m_status = MacStatus::INVALID_ADDRESS;
         if (!m_mcpsDataConfirmCallback.IsNull())
         {
             m_mcpsDataConfirmCallback(confirmParams);
@@ -467,7 +469,7 @@
     default:
         NS_LOG_ERROR(this << " Can not send packet with incorrect Destination Address mode = "
                           << params.m_dstAddrMode);
-        confirmParams.m_status = LrWpanMacStatus::INVALID_ADDRESS;
+        confirmParams.m_status = MacStatus::INVALID_ADDRESS;
         if (!m_mcpsDataConfirmCallback.IsNull())
         {
             m_mcpsDataConfirmCallback(confirmParams);
@@ -591,7 +593,7 @@
     if (GetShortAddress() == Mac16Address("ff:ff"))
     {
         NS_LOG_ERROR(this << " Invalid MAC short address");
-        confirmParams.m_status = LrWpanMacStatus::NO_SHORT_ADDRESS;
+        confirmParams.m_status = MacStatus::NO_SHORT_ADDRESS;
         if (!m_mlmeStartConfirmCallback.IsNull())
         {
             m_mlmeStartConfirmCallback(confirmParams);
@@ -601,7 +603,7 @@
 
     if ((params.m_bcnOrd > 15) || (params.m_sfrmOrd > params.m_bcnOrd))
     {
-        confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+        confirmParams.m_status = MacStatus::INVALID_PARAMETER;
         if (!m_mlmeStartConfirmCallback.IsNull())
         {
             m_mlmeStartConfirmCallback(confirmParams);
@@ -614,9 +616,9 @@
     m_pendPrimitive = MLME_START_REQ;
     m_startParams = params;
 
-    Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+    Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
     pibAttr->phyCurrentPage = m_startParams.m_logChPage;
-    m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentPage, pibAttr);
+    m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
 }
 
 void
@@ -628,11 +630,11 @@
     confirmParams.m_scanType = params.m_scanType;
     confirmParams.m_chPage = params.m_chPage;
 
-    if ((m_scanEvent.IsRunning() || m_scanEnergyEvent.IsRunning()) || m_scanOrphanEvent.IsRunning())
+    if ((m_scanEvent.IsPending() || m_scanEnergyEvent.IsPending()) || m_scanOrphanEvent.IsPending())
     {
         if (!m_mlmeScanConfirmCallback.IsNull())
         {
-            confirmParams.m_status = LrWpanMacStatus::SCAN_IN_PROGRESS;
+            confirmParams.m_status = MacStatus::SCAN_IN_PROGRESS;
             m_mlmeScanConfirmCallback(confirmParams);
         }
         NS_LOG_ERROR(this << " A channel scan is already in progress");
@@ -643,7 +645,7 @@
     {
         if (!m_mlmeScanConfirmCallback.IsNull())
         {
-            confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+            confirmParams.m_status = MacStatus::INVALID_PARAMETER;
             m_mlmeScanConfirmCallback(confirmParams);
         }
         NS_LOG_ERROR(this << "Invalid scan duration or unsupported scan type");
@@ -674,9 +676,9 @@
     m_scanParams = params;
     m_pendPrimitive = MLME_SCAN_REQ;
 
-    Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+    Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
     pibAttr->phyCurrentPage = params.m_chPage;
-    m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentPage, pibAttr);
+    m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
 }
 
 void
@@ -722,15 +724,15 @@
         {
             MlmeAssociateConfirmParams confirmParams;
             confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
-            confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+            confirmParams.m_status = MacStatus::INVALID_PARAMETER;
             m_mlmeAssociateConfirmCallback(confirmParams);
         }
     }
     else
     {
-        Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+        Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
         pibAttr->phyCurrentPage = params.m_chPage;
-        m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentPage, pibAttr);
+        m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
     }
 }
 
@@ -867,9 +869,9 @@
 
     auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
     // change phy current logical channel
-    Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+    Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
     pibAttr->phyCurrentChannel = params.m_logCh;
-    m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentChannel, pibAttr);
+    m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
 
     // Enable Phy receiver
     m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
@@ -877,7 +879,7 @@
     uint64_t searchSymbols;
     Time searchBeaconTime;
 
-    if (m_trackingEvent.IsRunning())
+    if (m_trackingEvent.IsPending())
     {
         m_trackingEvent.Cancel();
     }
@@ -915,17 +917,17 @@
 }
 
 void
-LrWpanMac::MlmeSetRequest(LrWpanMacPibAttributeIdentifier id, Ptr<LrWpanMacPibAttributes> attribute)
+LrWpanMac::MlmeSetRequest(MacPibAttributeIdentifier id, Ptr<MacPibAttributes> attribute)
 {
     MlmeSetConfirmParams confirmParams;
-    confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+    confirmParams.m_status = MacStatus::SUCCESS;
 
     switch (id)
     {
     case macBeaconPayload:
         if (attribute->macBeaconPayload->GetSize() > lrwpan::aMaxBeaconPayloadLength)
         {
-            confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+            confirmParams.m_status = MacStatus::INVALID_PARAMETER;
         }
         else
         {
@@ -934,20 +936,20 @@
         }
         break;
     case macBeaconPayloadLength:
-        confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+        confirmParams.m_status = MacStatus::INVALID_PARAMETER;
         break;
     case macShortAddress:
         m_shortAddress = attribute->macShortAddress;
         break;
     case macExtendedAddress:
-        confirmParams.m_status = LrWpanMacStatus::READ_ONLY;
+        confirmParams.m_status = MacStatus::READ_ONLY;
         break;
     case macPanId:
         m_macPanId = macPanId;
         break;
     default:
         // TODO: Add support for setting other attributes
-        confirmParams.m_status = LrWpanMacStatus::UNSUPPORTED_ATTRIBUTE;
+        confirmParams.m_status = MacStatus::UNSUPPORTED_ATTRIBUTE;
         break;
     }
 
@@ -959,10 +961,10 @@
 }
 
 void
-LrWpanMac::MlmeGetRequest(LrWpanMacPibAttributeIdentifier id)
+LrWpanMac::MlmeGetRequest(MacPibAttributeIdentifier id)
 {
-    LrWpanMacStatus status = LrWpanMacStatus::SUCCESS;
-    Ptr<LrWpanMacPibAttributes> attributes = Create<LrWpanMacPibAttributes>();
+    MacStatus status = MacStatus::SUCCESS;
+    Ptr<MacPibAttributes> attributes = Create<MacPibAttributes>();
 
     switch (id)
     {
@@ -976,7 +978,7 @@
         attributes->macShortAddress = m_shortAddress;
         break;
     case macExtendedAddress:
-        attributes->macExtendedAddress = m_selfExt;
+        attributes->macExtendedAddress = m_macExtendedAddress;
         break;
     case macPanId:
         attributes->macPanId = m_macPanId;
@@ -988,7 +990,7 @@
         attributes->pCurrentPage = m_phy->GetCurrentPage();
         break;
     default:
-        status = LrWpanMacStatus::UNSUPPORTED_ATTRIBUTE;
+        status = MacStatus::UNSUPPORTED_ATTRIBUTE;
         break;
     }
 
@@ -1002,7 +1004,7 @@
 LrWpanMac::SendOneBeacon()
 {
     NS_LOG_FUNCTION(this);
-    NS_ASSERT(m_lrWpanMacState == MAC_IDLE);
+    NS_ASSERT(m_macState == MAC_IDLE);
 
     LrWpanMacHeader macHdr(LrWpanMacHeader::LRWPAN_MAC_BEACON, m_macBsn.GetValue());
     m_macBsn++;
@@ -1221,7 +1223,7 @@
 
     // Mac Header values (Section 5.3.5)
     macHdr.SetSrcAddrMode(LrWpanMacHeader::EXTADDR);
-    macHdr.SetSrcAddrFields(0xffff, m_selfExt);
+    macHdr.SetSrcAddrFields(0xffff, m_macExtendedAddress);
 
     if (m_macCoordShortAddress == Mac16Address("ff:fe"))
     {
@@ -1295,7 +1297,7 @@
     {
         MlmeAssociateConfirmParams confirmParams;
         confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
-        confirmParams.m_status = LrWpanMacStatus::NO_DATA;
+        confirmParams.m_status = MacStatus::NO_DATA;
         m_mlmeAssociateConfirmCallback(confirmParams);
     }
 }
@@ -1349,7 +1351,7 @@
             if (!m_mlmeStartConfirmCallback.IsNull())
             {
                 MlmeStartConfirmParams confirmParams;
-                confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                confirmParams.m_status = MacStatus::SUCCESS;
                 m_mlmeStartConfirmCallback(confirmParams);
             }
 
@@ -1403,9 +1405,9 @@
     if (channelFound)
     {
         // Switch to the next channel in the list and restart scan
-        Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+        Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
         pibAttr->phyCurrentChannel = m_channelScanIndex;
-        m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentChannel, pibAttr);
+        m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
     }
     else
     {
@@ -1432,12 +1434,12 @@
             {
                 confirmParams.m_panDescList = m_panDescriptorList;
             }
-            confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+            confirmParams.m_status = MacStatus::SUCCESS;
             break;
         case MLMESCAN_ACTIVE:
             if (m_panDescriptorList.empty())
             {
-                confirmParams.m_status = LrWpanMacStatus::NO_BEACON;
+                confirmParams.m_status = MacStatus::NO_BEACON;
             }
             else
             {
@@ -1445,12 +1447,12 @@
                 {
                     confirmParams.m_panDescList = m_panDescriptorList;
                 }
-                confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                confirmParams.m_status = MacStatus::SUCCESS;
             }
             break;
         case MLMESCAN_ORPHAN:
             confirmParams.m_panDescList = {};
-            confirmParams.m_status = LrWpanMacStatus::NO_BEACON;
+            confirmParams.m_status = MacStatus::NO_BEACON;
             confirmParams.m_resultListSize = 0;
             // The device lost track of the coordinator and was unable
             // to locate it, disassociate from the network.
@@ -1498,9 +1500,9 @@
     if (channelFound)
     {
         // switch to the next channel in the list and restart scan
-        Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+        Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
         pibAttr->phyCurrentChannel = m_channelScanIndex;
-        m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentChannel, pibAttr);
+        m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
     }
     else
     {
@@ -1514,7 +1516,7 @@
 
         // All channels scanned, report success
         MlmeScanConfirmParams confirmParams;
-        confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+        confirmParams.m_status = MacStatus::SUCCESS;
         confirmParams.m_chPage = m_phy->GetCurrentPage();
         confirmParams.m_scanType = m_scanParams.m_scanType;
         confirmParams.m_energyDetList = m_energyDetectList;
@@ -1689,7 +1691,7 @@
     {
         MlmeSyncLossIndicationParams syncLossParams;
         // syncLossParams.m_logCh =
-        syncLossParams.m_lossReason = LrWpanMacStatus::BEACON_LOSS;
+        syncLossParams.m_lossReason = MacStatus::BEACON_LOSS;
         syncLossParams.m_panId = m_macPanId;
         m_mlmeSyncLossIndicationCallback(syncLossParams);
 
@@ -1716,13 +1718,13 @@
 {
     NS_LOG_FUNCTION(this);
     // Pull a packet from the queue and start sending if we are not already sending.
-    if (m_lrWpanMacState == MAC_IDLE && !m_txQueue.empty() && !m_setMacState.IsRunning())
+    if (m_macState == MAC_IDLE && !m_txQueue.empty() && !m_setMacState.IsPending())
     {
         if (m_csmaCa->IsUnSlottedCsmaCa() || (m_outSuperframeStatus == CAP && m_coor) ||
             m_incSuperframeStatus == CAP)
         {
             // check MAC is not in a IFS
-            if (!m_ifsEvent.IsRunning())
+            if (!m_ifsEvent.IsPending())
             {
                 Ptr<TxQueueElement> txQElement = m_txQueue.front();
                 m_txPkt = txQElement->txQPkt;
@@ -1802,8 +1804,7 @@
 void
 LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr<Packet> p, uint8_t lqi)
 {
-    NS_ASSERT(m_lrWpanMacState == MAC_IDLE || m_lrWpanMacState == MAC_ACK_PENDING ||
-              m_lrWpanMacState == MAC_CSMA);
+    NS_ASSERT(m_macState == MAC_IDLE || m_macState == MAC_ACK_PENDING || m_macState == MAC_CSMA);
     NS_LOG_FUNCTION(this << psduLength << p << (uint16_t)lqi);
 
     bool acceptFrame;
@@ -1942,24 +1943,24 @@
 
             if (acceptFrame && (receivedMacHdr.GetDstAddrMode() == EXT_ADDR))
             {
-                acceptFrame = (receivedMacHdr.GetExtDstAddr() == m_selfExt);
+                acceptFrame = (receivedMacHdr.GetExtDstAddr() == m_macExtendedAddress);
             }
 
-            if (acceptFrame && m_scanEvent.IsRunning())
+            if (acceptFrame && m_scanEvent.IsPending())
             {
                 if (!receivedMacHdr.IsBeacon())
                 {
                     acceptFrame = false;
                 }
             }
-            else if (acceptFrame && m_scanOrphanEvent.IsRunning())
+            else if (acceptFrame && m_scanOrphanEvent.IsPending())
             {
                 if (!receivedMacHdr.IsCommand())
                 {
                     acceptFrame = false;
                 }
             }
-            else if (m_scanEnergyEvent.IsRunning())
+            else if (m_scanEnergyEvent.IsPending())
             {
                 // Reject any frames if energy scan is running
                 acceptFrame = false;
@@ -1984,7 +1985,7 @@
                 // Although ACKs do not use CSMA to to be transmitted, we need to make sure
                 // that the transmitted ACK will not collide with the transmission of a beacon
                 // when beacon-enabled mode is running in the coordinator.
-                if (acceptFrame && (m_csmaCa->IsSlottedCsmaCa() && m_capEvent.IsRunning()))
+                if (acceptFrame && (m_csmaCa->IsSlottedCsmaCa() && m_capEvent.IsPending()))
                 {
                     Time timeLeftInCap = Simulator::GetDelayLeft(m_capEvent);
                     uint64_t ackSymbols = lrwpan::aTurnaroundTime + m_phy->GetPhySHRDuration() +
@@ -2020,12 +2021,12 @@
                     // multicast, with ack req set, generate and send an ack frame. If there is a
                     // CSMA medium access in progress we cancel the medium access for sending the
                     // ACK frame. A new transmission attempt will be started after the ACK was send.
-                    if (m_lrWpanMacState == MAC_ACK_PENDING)
+                    if (m_macState == MAC_ACK_PENDING)
                     {
                         m_ackWaitTimeout.Cancel();
                         PrepareRetransmission();
                     }
-                    else if (m_lrWpanMacState == MAC_CSMA)
+                    else if (m_macState == MAC_CSMA)
                     {
                         // \todo: If we receive a packet while doing CSMA/CA, should  we drop the
                         // packet because of channel busy,
@@ -2122,7 +2123,7 @@
                     panDescriptor.m_timeStamp = m_macBeaconRxTime;
 
                     // Process beacon when device belongs to a PAN (associated device)
-                    if (!m_scanEvent.IsRunning() && m_macPanId == receivedMacHdr.GetDstPanId())
+                    if (!m_scanEvent.IsPending() && m_macPanId == receivedMacHdr.GetDstPanId())
                     {
                         // We need to make sure to cancel any possible ongoing unslotted CSMA/CA
                         // operations when receiving a beacon (e.g. Those taking place at the
@@ -2177,7 +2178,7 @@
                         m_setMacState =
                             Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE);
                     }
-                    else if (!m_scanEvent.IsRunning() && m_macPanId == 0xFFFF)
+                    else if (!m_scanEvent.IsPending() && m_macPanId == 0xFFFF)
                     {
                         NS_LOG_DEBUG(this << " Device not associated, cannot process beacon");
                     }
@@ -2198,7 +2199,7 @@
                             }
                         }
 
-                        if (m_scanEvent.IsRunning())
+                        if (m_scanEvent.IsPending())
                         {
                             // Channel scanning is taking place, save only unique PAN descriptors
                             bool descriptorExists = false;
@@ -2235,7 +2236,7 @@
                             }
                             return;
                         }
-                        else if (m_trackingEvent.IsRunning())
+                        else if (m_trackingEvent.IsPending())
                         {
                             // check if MLME-SYNC.request was previously issued and running
                             // Sync. is necessary to handle pending messages (indirect
@@ -2317,7 +2318,7 @@
                         }
                         break;
                     case CommandPayloadHeader::COOR_REALIGN:
-                        if (m_scanOrphanEvent.IsRunning())
+                        if (m_scanOrphanEvent.IsPending())
                         {
                             // Coordinator located, no need to keep scanning other channels
                             m_scanOrphanEvent.Cancel();
@@ -2338,7 +2339,7 @@
                                 MlmeScanConfirmParams confirmParams;
                                 confirmParams.m_scanType = m_scanParams.m_scanType;
                                 confirmParams.m_chPage = m_scanParams.m_chPage;
-                                confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                                confirmParams.m_status = MacStatus::SUCCESS;
                                 m_mlmeScanConfirmCallback(confirmParams);
                             }
                             m_scanParams = {};
@@ -2358,7 +2359,7 @@
                     m_mcpsDataIndicationCallback(params, p);
                 }
                 else if (receivedMacHdr.IsAcknowledgment() && m_txPkt &&
-                         m_lrWpanMacState == MAC_ACK_PENDING)
+                         m_macState == MAC_ACK_PENDING)
                 {
                     LrWpanMacHeader peekedMacHdr;
                     m_txPkt->PeekHeader(peekedMacHdr);
@@ -2418,7 +2419,7 @@
                                     commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
                                     commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
                                     commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
-                                    commStatusParams.m_status = LrWpanMacStatus::SUCCESS;
+                                    commStatusParams.m_status = MacStatus::SUCCESS;
                                     m_mlmeCommStatusIndicationCallback(commStatusParams);
                                 }
                                 // Remove element from Pending Transaction List
@@ -2440,7 +2441,7 @@
                                 if (!m_mlmePollConfirmCallback.IsNull())
                                 {
                                     MlmePollConfirmParams pollConfirmParams;
-                                    pollConfirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                                    pollConfirmParams.m_status = MacStatus::SUCCESS;
                                     m_mlmePollConfirmCallback(pollConfirmParams);
                                 }
                                 break;
@@ -2458,7 +2459,7 @@
                                     commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
                                     commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
                                     commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
-                                    commStatusParams.m_status = LrWpanMacStatus::SUCCESS;
+                                    commStatusParams.m_status = MacStatus::SUCCESS;
                                     m_mlmeCommStatusIndicationCallback(commStatusParams);
                                 }
                             }
@@ -2476,7 +2477,7 @@
                                 Ptr<TxQueueElement> txQElement = m_txQueue.front();
                                 McpsDataConfirmParams confirmParams;
                                 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
-                                confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                                confirmParams.m_status = MacStatus::SUCCESS;
                                 m_mcpsDataConfirmCallback(confirmParams);
                             }
                         }
@@ -2527,7 +2528,7 @@
 {
     NS_LOG_FUNCTION(this << static_cast<uint32_t>(seqno));
 
-    NS_ASSERT(m_lrWpanMacState == MAC_IDLE);
+    NS_ASSERT(m_macState == MAC_IDLE);
 
     // Generate a corresponding ACK Frame.
     LrWpanMacHeader macHdr(LrWpanMacHeader::LRWPAN_MAC_ACKNOWLEDGMENT, seqno);
@@ -2565,7 +2566,7 @@
         {
             McpsDataConfirmParams confirmParams;
             confirmParams.m_msduHandle = txQElement->txQMsduHandle;
-            confirmParams.m_status = LrWpanMacStatus::TRANSACTION_OVERFLOW;
+            confirmParams.m_status = MacStatus::TRANSACTION_OVERFLOW;
             m_mcpsDataConfirmCallback(confirmParams);
         }
         NS_LOG_DEBUG("TX Queue with size " << m_txQueue.size() << " is full, dropping packet");
@@ -2680,7 +2681,7 @@
                 {
                     MlmeAssociateConfirmParams confirmParams;
                     confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
-                    confirmParams.m_status = LrWpanMacStatus::NO_ACK;
+                    confirmParams.m_status = MacStatus::NO_ACK;
                     m_mlmeAssociateConfirmCallback(confirmParams);
                 }
                 break;
@@ -2695,7 +2696,7 @@
                     commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
                     commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
                     commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
-                    commStatusParams.m_status = LrWpanMacStatus::NO_ACK;
+                    commStatusParams.m_status = MacStatus::NO_ACK;
                     m_mlmeCommStatusIndicationCallback(commStatusParams);
                 }
                 RemovePendTxQElement(m_txPkt->Copy());
@@ -2715,7 +2716,7 @@
                 if (!m_mlmePollConfirmCallback.IsNull())
                 {
                     MlmePollConfirmParams pollConfirmParams;
-                    pollConfirmParams.m_status = LrWpanMacStatus::NO_ACK;
+                    pollConfirmParams.m_status = MacStatus::NO_ACK;
                     m_mlmePollConfirmCallback(pollConfirmParams);
                 }
                 break;
@@ -2736,7 +2737,7 @@
             {
                 McpsDataConfirmParams confirmParams;
                 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
-                confirmParams.m_status = LrWpanMacStatus::NO_ACK;
+                confirmParams.m_status = MacStatus::NO_ACK;
                 m_mcpsDataConfirmCallback(confirmParams);
             }
         }
@@ -2812,7 +2813,7 @@
             commStatusParams.m_srcExtAddr = peekedMacHdr.GetExtSrcAddr();
             commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
             commStatusParams.m_dstExtAddr = peekedMacHdr.GetExtDstAddr();
-            commStatusParams.m_status = LrWpanMacStatus::TRANSACTION_OVERFLOW;
+            commStatusParams.m_status = MacStatus::TRANSACTION_OVERFLOW;
             m_mlmeCommStatusIndicationCallback(commStatusParams);
         }
         m_macIndTxDropTrace(p);
@@ -2859,7 +2860,7 @@
                     commStatusParams.m_srcExtAddr = peekedMacHdr.GetExtSrcAddr();
                     commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
                     commStatusParams.m_dstExtAddr = peekedMacHdr.GetExtDstAddr();
-                    commStatusParams.m_status = LrWpanMacStatus::TRANSACTION_EXPIRED;
+                    commStatusParams.m_status = MacStatus::TRANSACTION_EXPIRED;
                     m_mlmeCommStatusIndicationCallback(commStatusParams);
                 }
             }
@@ -2869,7 +2870,7 @@
                 if (!m_mcpsDataConfirmCallback.IsNull())
                 {
                     McpsDataConfirmParams confParams;
-                    confParams.m_status = LrWpanMacStatus::TRANSACTION_EXPIRED;
+                    confParams.m_status = MacStatus::TRANSACTION_EXPIRED;
                     m_mcpsDataConfirmCallback(confParams);
                 }
             }
@@ -2991,9 +2992,9 @@
 }
 
 void
-LrWpanMac::PdDataConfirm(LrWpanPhyEnumeration status)
+LrWpanMac::PdDataConfirm(PhyEnumeration status)
 {
-    NS_ASSERT(m_lrWpanMacState == MAC_SENDING);
+    NS_ASSERT(m_macState == MAC_SENDING);
     NS_LOG_FUNCTION(this << status << m_txQueue.size());
 
     LrWpanMacHeader macHdr;
@@ -3033,7 +3034,7 @@
                     if (!m_mlmeStartConfirmCallback.IsNull())
                     {
                         MlmeStartConfirmParams mlmeConfirmParams;
-                        mlmeConfirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                        mlmeConfirmParams.m_status = MacStatus::SUCCESS;
                         m_mlmeStartConfirmCallback(mlmeConfirmParams);
                     }
                 }
@@ -3083,7 +3084,7 @@
                         commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
                         commStatusParams.m_dstShortAddr = macHdr.GetShortDstAddr();
 
-                        commStatusParams.m_status = LrWpanMacStatus::SUCCESS;
+                        commStatusParams.m_status = MacStatus::SUCCESS;
                         m_mlmeCommStatusIndicationCallback(commStatusParams);
                     }
                 }
@@ -3101,7 +3102,7 @@
                     NS_ASSERT_MSG(!m_txQueue.empty(), "TxQsize = 0");
                     Ptr<TxQueueElement> txQElement = m_txQueue.front();
                     confirmParams.m_msduHandle = txQElement->txQMsduHandle;
-                    confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                    confirmParams.m_status = MacStatus::SUCCESS;
                     m_mcpsDataConfirmCallback(confirmParams);
                 }
                 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
@@ -3146,18 +3147,18 @@
                 {
                     MlmeAssociateConfirmParams confirmParams;
 
-                    switch (static_cast<LrWpanMacStatus>(receivedMacPayload.GetAssociationStatus()))
+                    switch (static_cast<MacStatus>(receivedMacPayload.GetAssociationStatus()))
                     {
-                    case LrWpanMacStatus::SUCCESS:
+                    case MacStatus::SUCCESS:
                         // The assigned short address by the coordinator
                         SetShortAddress(receivedMacPayload.GetShortAddr());
                         m_macPanId = receivedMacHdr.GetSrcPanId();
 
-                        confirmParams.m_status = LrWpanMacStatus::SUCCESS;
+                        confirmParams.m_status = MacStatus::SUCCESS;
                         confirmParams.m_assocShortAddr = GetShortAddress();
                         break;
-                    case LrWpanMacStatus::FULL_CAPACITY:
-                        confirmParams.m_status = LrWpanMacStatus::FULL_CAPACITY;
+                    case MacStatus::FULL_CAPACITY:
+                        confirmParams.m_status = MacStatus::FULL_CAPACITY;
                         m_macPanId = 0xffff;
                         m_macCoordShortAddress = Mac16Address("FF:FF");
                         m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
@@ -3167,9 +3168,9 @@
                         m_incomingBeaconOrder = 15;
                         m_incomingSuperframeOrder = 15;
                         break;
-                    case LrWpanMacStatus::ACCESS_DENIED:
+                    case MacStatus::ACCESS_DENIED:
                     default:
-                        confirmParams.m_status = LrWpanMacStatus::ACCESS_DENIED;
+                        confirmParams.m_status = MacStatus::ACCESS_DENIED;
                         m_macPanId = 0xffff;
                         m_macCoordShortAddress = Mac16Address("FF:FF");
                         m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
@@ -3210,7 +3211,7 @@
             {
                 McpsDataConfirmParams confirmParams;
                 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
-                confirmParams.m_status = LrWpanMacStatus::FRAME_TOO_LONG;
+                confirmParams.m_status = MacStatus::FRAME_TOO_LONG;
                 m_mcpsDataConfirmCallback(confirmParams);
             }
             RemoveFirstTxQElement();
@@ -3238,7 +3239,7 @@
 }
 
 void
-LrWpanMac::PlmeCcaConfirm(LrWpanPhyEnumeration status)
+LrWpanMac::PlmeCcaConfirm(PhyEnumeration status)
 {
     NS_LOG_FUNCTION(this << status);
     // Direct this call through the csmaCa object
@@ -3246,7 +3247,7 @@
 }
 
 void
-LrWpanMac::PlmeEdConfirm(LrWpanPhyEnumeration status, uint8_t energyLevel)
+LrWpanMac::PlmeEdConfirm(PhyEnumeration status, uint8_t energyLevel)
 {
     NS_LOG_FUNCTION(this << status << energyLevel);
 
@@ -3263,19 +3264,19 @@
 }
 
 void
-LrWpanMac::PlmeGetAttributeConfirm(LrWpanPhyEnumeration status,
-                                   LrWpanPibAttributeIdentifier id,
-                                   Ptr<LrWpanPhyPibAttributes> attribute)
+LrWpanMac::PlmeGetAttributeConfirm(PhyEnumeration status,
+                                   PhyPibAttributeIdentifier id,
+                                   Ptr<PhyPibAttributes> attribute)
 {
     NS_LOG_FUNCTION(this << status << id << attribute);
 }
 
 void
-LrWpanMac::PlmeSetTRXStateConfirm(LrWpanPhyEnumeration status)
+LrWpanMac::PlmeSetTRXStateConfirm(PhyEnumeration status)
 {
     NS_LOG_FUNCTION(this << status);
 
-    if (m_lrWpanMacState == MAC_SENDING &&
+    if (m_macState == MAC_SENDING &&
         (status == IEEE_802_15_4_PHY_TX_ON || status == IEEE_802_15_4_PHY_SUCCESS))
     {
         NS_ASSERT(m_txPkt);
@@ -3286,18 +3287,18 @@
         m_macTxTrace(m_txPkt);
         m_phy->PdDataRequest(m_txPkt->GetSize(), m_txPkt);
     }
-    else if (m_lrWpanMacState == MAC_CSMA &&
+    else if (m_macState == MAC_CSMA &&
              (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS))
     {
         // Start the CSMA algorithm as soon as the receiver is enabled.
         m_csmaCa->Start();
     }
-    else if (m_lrWpanMacState == MAC_IDLE)
+    else if (m_macState == MAC_IDLE)
     {
         NS_ASSERT(status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS ||
                   status == IEEE_802_15_4_PHY_TRX_OFF);
 
-        if (status == IEEE_802_15_4_PHY_RX_ON && m_scanEnergyEvent.IsRunning())
+        if (status == IEEE_802_15_4_PHY_RX_ON && m_scanEnergyEvent.IsPending())
         {
             // Kick start Energy Detection Scan
             m_phy->PlmeEdRequest();
@@ -3308,7 +3309,7 @@
             CheckQueue();
         }
     }
-    else if (m_lrWpanMacState == MAC_ACK_PENDING)
+    else if (m_macState == MAC_ACK_PENDING)
     {
         NS_ASSERT(status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS);
     }
@@ -3322,12 +3323,12 @@
 }
 
 void
-LrWpanMac::PlmeSetAttributeConfirm(LrWpanPhyEnumeration status, LrWpanPibAttributeIdentifier id)
+LrWpanMac::PlmeSetAttributeConfirm(PhyEnumeration status, PhyPibAttributeIdentifier id)
 {
     NS_LOG_FUNCTION(this << status << id);
-    if (id == LrWpanPibAttributeIdentifier::phyCurrentPage && m_pendPrimitive == MLME_SCAN_REQ)
+    if (id == PhyPibAttributeIdentifier::phyCurrentPage && m_pendPrimitive == MLME_SCAN_REQ)
     {
-        if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
+        if (status == PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
             // get the first channel to scan from scan channel list
             bool channelFound = false;
@@ -3343,9 +3344,9 @@
 
             if (channelFound)
             {
-                Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+                Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
                 pibAttr->phyCurrentChannel = m_channelScanIndex;
-                m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentChannel,
+                m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel,
                                                pibAttr);
             }
         }
@@ -3356,16 +3357,15 @@
                 MlmeScanConfirmParams confirmParams;
                 confirmParams.m_scanType = m_scanParams.m_scanType;
                 confirmParams.m_chPage = m_scanParams.m_chPage;
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 m_mlmeScanConfirmCallback(confirmParams);
             }
             NS_LOG_ERROR(this << "Channel Scan: Invalid channel page");
         }
     }
-    else if (id == LrWpanPibAttributeIdentifier::phyCurrentChannel &&
-             m_pendPrimitive == MLME_SCAN_REQ)
+    else if (id == PhyPibAttributeIdentifier::phyCurrentChannel && m_pendPrimitive == MLME_SCAN_REQ)
     {
-        if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
+        if (status == PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
             auto symbolRate = static_cast<uint64_t>(m_phy->GetDataOrSymbolRate(false));
             Time nextScanTime;
@@ -3410,7 +3410,7 @@
                 MlmeScanConfirmParams confirmParams;
                 confirmParams.m_scanType = m_scanParams.m_scanType;
                 confirmParams.m_chPage = m_scanParams.m_chPage;
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 if (!m_mlmeScanConfirmCallback.IsNull())
                 {
                     m_mlmeScanConfirmCallback(confirmParams);
@@ -3426,38 +3426,36 @@
                 MlmeScanConfirmParams confirmParams;
                 confirmParams.m_scanType = m_scanParams.m_scanType;
                 confirmParams.m_chPage = m_scanParams.m_chPage;
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 m_mlmeScanConfirmCallback(confirmParams);
             }
             NS_LOG_ERROR("Channel " << m_channelScanIndex
                                     << " could not be set in the current page");
         }
     }
-    else if (id == LrWpanPibAttributeIdentifier::phyCurrentPage &&
-             m_pendPrimitive == MLME_START_REQ)
+    else if (id == PhyPibAttributeIdentifier::phyCurrentPage && m_pendPrimitive == MLME_START_REQ)
     {
-        if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
+        if (status == PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
-            Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+            Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
             pibAttr->phyCurrentChannel = m_startParams.m_logCh;
-            m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentChannel,
-                                           pibAttr);
+            m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
         }
         else
         {
             if (!m_mlmeStartConfirmCallback.IsNull())
             {
                 MlmeStartConfirmParams confirmParams;
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 m_mlmeStartConfirmCallback(confirmParams);
             }
             NS_LOG_ERROR("Invalid page parameter in MLME-start");
         }
     }
-    else if (id == LrWpanPibAttributeIdentifier::phyCurrentChannel &&
+    else if (id == PhyPibAttributeIdentifier::phyCurrentChannel &&
              m_pendPrimitive == MLME_START_REQ)
     {
-        if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
+        if (status == PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
             EndStartRequest();
         }
@@ -3466,21 +3464,19 @@
             if (!m_mlmeStartConfirmCallback.IsNull())
             {
                 MlmeStartConfirmParams confirmParams;
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 m_mlmeStartConfirmCallback(confirmParams);
             }
             NS_LOG_ERROR("Invalid channel parameter in MLME-start");
         }
     }
-    else if (id == LrWpanPibAttributeIdentifier::phyCurrentPage &&
-             m_pendPrimitive == MLME_ASSOC_REQ)
+    else if (id == PhyPibAttributeIdentifier::phyCurrentPage && m_pendPrimitive == MLME_ASSOC_REQ)
     {
-        if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
+        if (status == PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
-            Ptr<LrWpanPhyPibAttributes> pibAttr = Create<LrWpanPhyPibAttributes>();
+            Ptr<PhyPibAttributes> pibAttr = Create<PhyPibAttributes>();
             pibAttr->phyCurrentChannel = m_associateParams.m_chNum;
-            m_phy->PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier::phyCurrentChannel,
-                                           pibAttr);
+            m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
         }
         else
         {
@@ -3497,16 +3493,16 @@
             {
                 MlmeAssociateConfirmParams confirmParams;
                 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 m_mlmeAssociateConfirmCallback(confirmParams);
             }
             NS_LOG_ERROR("Invalid page parameter in MLME-associate");
         }
     }
-    else if (id == LrWpanPibAttributeIdentifier::phyCurrentChannel &&
+    else if (id == PhyPibAttributeIdentifier::phyCurrentChannel &&
              m_pendPrimitive == MLME_ASSOC_REQ)
     {
-        if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
+        if (status == PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS)
         {
             EndAssociateRequest();
         }
@@ -3525,7 +3521,7 @@
             {
                 MlmeAssociateConfirmParams confirmParams;
                 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
-                confirmParams.m_status = LrWpanMacStatus::INVALID_PARAMETER;
+                confirmParams.m_status = MacStatus::INVALID_PARAMETER;
                 m_mlmeAssociateConfirmCallback(confirmParams);
             }
             NS_LOG_ERROR("Invalid channel parameter in MLME-associate");
@@ -3534,7 +3530,7 @@
 }
 
 void
-LrWpanMac::SetLrWpanMacState(LrWpanMacState macState)
+LrWpanMac::SetLrWpanMacState(MacState macState)
 {
     NS_LOG_FUNCTION(this << "mac state = " << macState);
 
@@ -3557,17 +3553,17 @@
     }
     else if (macState == MAC_CSMA)
     {
-        NS_ASSERT(m_lrWpanMacState == MAC_IDLE || m_lrWpanMacState == MAC_ACK_PENDING);
+        NS_ASSERT(m_macState == MAC_IDLE || m_macState == MAC_ACK_PENDING);
         ChangeMacState(MAC_CSMA);
         m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
     }
-    else if (m_lrWpanMacState == MAC_CSMA && macState == CHANNEL_IDLE)
+    else if (m_macState == MAC_CSMA && macState == CHANNEL_IDLE)
     {
         // Channel is idle, set transmitter to TX_ON
         ChangeMacState(MAC_SENDING);
         m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
     }
-    else if (m_lrWpanMacState == MAC_CSMA && macState == CHANNEL_ACCESS_FAILURE)
+    else if (m_macState == MAC_CSMA && macState == CHANNEL_ACCESS_FAILURE)
     {
         NS_ASSERT(m_txPkt);
 
@@ -3602,7 +3598,7 @@
                 {
                     MlmeAssociateConfirmParams confirmParams;
                     confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
-                    confirmParams.m_status = LrWpanMacStatus::CHANNEL_ACCESS_FAILURE;
+                    confirmParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
                     m_mlmeAssociateConfirmCallback(confirmParams);
                 }
                 break;
@@ -3616,7 +3612,7 @@
                     commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
                     commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
                     commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
-                    commStatusParams.m_status = LrWpanMacStatus::CHANNEL_ACCESS_FAILURE;
+                    commStatusParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
                     m_mlmeCommStatusIndicationCallback(commStatusParams);
                 }
                 RemovePendTxQElement(m_txPkt->Copy());
@@ -3635,7 +3631,7 @@
                 if (!m_mlmePollConfirmCallback.IsNull())
                 {
                     MlmePollConfirmParams pollConfirmParams;
-                    pollConfirmParams.m_status = LrWpanMacStatus::CHANNEL_ACCESS_FAILURE;
+                    pollConfirmParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
                     m_mlmePollConfirmCallback(pollConfirmParams);
                 }
                 break;
@@ -3649,13 +3645,13 @@
                     commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
                     commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
                     commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
-                    commStatusParams.m_status = LrWpanMacStatus::CHANNEL_ACCESS_FAILURE;
+                    commStatusParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
                     m_mlmeCommStatusIndicationCallback(commStatusParams);
                 }
                 break;
             }
             case CommandPayloadHeader::ORPHAN_NOTIF: {
-                if (m_scanOrphanEvent.IsRunning())
+                if (m_scanOrphanEvent.IsPending())
                 {
                     m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum());
                 }
@@ -3664,7 +3660,7 @@
                 break;
             }
             case CommandPayloadHeader::BEACON_REQ: {
-                if (m_scanEvent.IsRunning())
+                if (m_scanEvent.IsPending())
                 {
                     m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum());
                 }
@@ -3685,7 +3681,7 @@
             {
                 McpsDataConfirmParams confirmParams;
                 confirmParams.m_msduHandle = m_txQueue.front()->txQMsduHandle;
-                confirmParams.m_status = LrWpanMacStatus::CHANNEL_ACCESS_FAILURE;
+                confirmParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
                 m_mcpsDataConfirmCallback(confirmParams);
             }
             // remove the copy of the packet that was just sent
@@ -3709,7 +3705,7 @@
             m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
         }
     }
-    else if (m_lrWpanMacState == MAC_CSMA && macState == MAC_CSMA_DEFERRED)
+    else if (m_macState == MAC_CSMA && macState == MAC_CSMA_DEFERRED)
     {
         ChangeMacState(MAC_IDLE);
         m_txPkt = nullptr;
@@ -3759,12 +3755,11 @@
 }
 
 void
-LrWpanMac::ChangeMacState(LrWpanMacState newState)
+LrWpanMac::ChangeMacState(MacState newState)
 {
-    NS_LOG_LOGIC(this << " change lrwpan mac state from " << m_lrWpanMacState << " to "
-                      << newState);
-    m_macStateLogger(m_lrWpanMacState, newState);
-    m_lrWpanMacState = newState;
+    NS_LOG_LOGIC(this << " change lrwpan mac state from " << m_macState << " to " << newState);
+    m_macStateLogger(m_macState, newState);
+    m_macState = newState;
 }
 
 uint64_t
@@ -3793,7 +3788,7 @@
 }
 
 bool
-LrWpanMac::isCoordDest()
+LrWpanMac::IsCoordDest()
 {
     NS_ASSERT(m_txPkt);
     LrWpanMacHeader macHdr;
@@ -3853,7 +3848,7 @@
 }
 
 bool
-LrWpanMac::isTxAckReq()
+LrWpanMac::IsTxAckReq()
 {
     NS_ASSERT(m_txPkt);
     LrWpanMacHeader macHdr;
@@ -3862,4 +3857,5 @@
     return macHdr.IsAckReq();
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac.h ns-3.42/src/lr-wpan/model/lr-wpan-mac.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac.h	2024-05-29 15:29:46.976073300 -0700
@@ -39,8 +39,11 @@
 
 namespace ns3
 {
-
 class Packet;
+
+namespace lrwpan
+{
+
 class LrWpanCsmaCa;
 
 /**
@@ -55,7 +58,7 @@
  *
  * Tx options
  */
-enum LrWpanTxOption
+enum TxOption
 {
     TX_OPTION_NONE = 0,    //!< TX_OPTION_NONE
     TX_OPTION_ACK = 1,     //!< TX_OPTION_ACK
@@ -68,7 +71,7 @@
  *
  * MAC states
  */
-enum LrWpanMacState
+enum MacState
 {
     MAC_IDLE,               //!< MAC_IDLE
     MAC_CSMA,               //!< MAC_CSMA
@@ -83,13 +86,13 @@
 };
 
 /**
- *  Overloaded operator to print the value of a LrWpanMacState.
+ *  Overloaded operator to print the value of a MacState.
  *
  *  \param os The output stream
  *  \param state The text value of the PHY state
  *  \return The output stream with text value of the MAC state
  */
-std::ostream& operator<<(std::ostream& os, const LrWpanMacState& state);
+std::ostream& operator<<(std::ostream& os, const MacState& state);
 
 /**
  * \ingroup lr-wpan
@@ -134,12 +137,12 @@
 
 /**
  * \ingroup lr-wpan
- * TracedValue callback signature for LrWpanMacState.
+ * TracedValue callback signature for MacState.
  *
  * \param [in] oldValue original value of the traced variable
  * \param [in] newValue new value of the traced variable
  */
-typedef void (*LrWpanMacState)(LrWpanMacState oldValue, LrWpanMacState newValue);
+typedef void (*MacState)(MacState oldValue, MacState newValue);
 
 /**
  * \ingroup lr-wpan
@@ -260,10 +263,9 @@
 
     void MlmePollRequest(MlmePollRequestParams params) override;
 
-    void MlmeSetRequest(LrWpanMacPibAttributeIdentifier id,
-                        Ptr<LrWpanMacPibAttributes> attribute) override;
+    void MlmeSetRequest(MacPibAttributeIdentifier id, Ptr<MacPibAttributes> attribute) override;
 
-    void MlmeGetRequest(LrWpanMacPibAttributeIdentifier id) override;
+    void MlmeGetRequest(MacPibAttributeIdentifier id) override;
 
     /**
      * Set the CSMA/CA implementation to be used by the MAC.
@@ -306,14 +308,14 @@
      * \param status to report to MAC
      *        PHY PD-DATA.confirm status
      */
-    void PdDataConfirm(LrWpanPhyEnumeration status);
+    void PdDataConfirm(PhyEnumeration status);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.2
      * PLME-CCA.confirm status
      * \param status TRX_OFF, BUSY or IDLE
      */
-    void PlmeCcaConfirm(LrWpanPhyEnumeration status);
+    void PlmeCcaConfirm(PhyEnumeration status);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.4
@@ -321,7 +323,7 @@
      * \param status SUCCESS, TRX_OFF or TX_ON
      * \param energyLevel 0x00-0xff ED level for the channel
      */
-    void PlmeEdConfirm(LrWpanPhyEnumeration status, uint8_t energyLevel);
+    void PlmeEdConfirm(PhyEnumeration status, uint8_t energyLevel);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.6
@@ -331,9 +333,9 @@
      * \param id the attributed identifier
      * \param attribute the attribute value
      */
-    void PlmeGetAttributeConfirm(LrWpanPhyEnumeration status,
-                                 LrWpanPibAttributeIdentifier id,
-                                 Ptr<LrWpanPhyPibAttributes> attribute);
+    void PlmeGetAttributeConfirm(PhyEnumeration status,
+                                 PhyPibAttributeIdentifier id,
+                                 Ptr<PhyPibAttributes> attribute);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.8
@@ -341,7 +343,7 @@
      * Set PHY state
      * \param status in RX_ON,TRX_OFF,FORCE_TRX_OFF,TX_ON
      */
-    void PlmeSetTRXStateConfirm(LrWpanPhyEnumeration status);
+    void PlmeSetTRXStateConfirm(PhyEnumeration status);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.10
@@ -350,14 +352,14 @@
      * \param status SUCCESS, UNSUPPORTED_ATTRIBUTE, INVALID_PARAMETER, or READ_ONLY
      * \param id the attributed identifier
      */
-    void PlmeSetAttributeConfirm(LrWpanPhyEnumeration status, LrWpanPibAttributeIdentifier id);
+    void PlmeSetAttributeConfirm(PhyEnumeration status, PhyPibAttributeIdentifier id);
 
     /**
      * CSMA-CA algorithm calls back the MAC after executing channel assessment.
      *
      * \param macState indicate BUSY or IDLE channel condition
      */
-    void SetLrWpanMacState(LrWpanMacState macState);
+    void SetLrWpanMacState(MacState macState);
 
     /**
      * Set the max size of the transmit queue.
@@ -661,7 +663,7 @@
      *
      * \return True if m_txPkt (packet awaiting to be sent) destination is its coordinator
      */
-    bool isCoordDest();
+    bool IsCoordDest();
 
     /**
      * Check if the packet destination is its coordinator
@@ -696,7 +698,7 @@
      *
      *\return True if the Tx packet requires acknowledgment
      * */
-    bool isTxAckReq();
+    bool IsTxAckReq();
 
     /**
      * Print the Pending transaction list.
@@ -720,15 +722,15 @@
     typedef void (*SentTracedCallback)(Ptr<const Packet> packet, uint8_t retries, uint8_t backoffs);
 
     /**
-     * TracedCallback signature for LrWpanMacState change events.
+     * TracedCallback signature for MacState change events.
      *
      * \param [in] oldValue The original state value.
      * \param [in] newValue The new state value.
-     * \deprecated The LrWpanMacState is now accessible as the
+     * \deprecated The MacState is now accessible as the
      * TracedValue \c MacStateValue. The \c MacState TracedCallback will
      * be removed in a future release.
      */
-    typedef void (*StateTracedCallback)(LrWpanMacState oldState, LrWpanMacState newState);
+    typedef void (*StateTracedCallback)(MacState oldState, MacState newState);
 
   protected:
     // Inherited from Object.
@@ -879,7 +881,7 @@
      *
      * \param newState the new state
      */
-    void ChangeMacState(LrWpanMacState newState);
+    void ChangeMacState(MacState newState);
 
     /**
      * Handle an ACK timeout with a packet retransmission, if there are
@@ -1112,14 +1114,14 @@
     TracedCallback<Ptr<const Packet>> m_promiscSnifferTrace;
 
     /**
-     * A trace source that fires when the LrWpanMac changes states.
+     * A trace source that fires when the MAC changes states.
      * Parameters are the old mac state and the new mac state.
      *
      * \deprecated This TracedCallback is deprecated and will be
      * removed in a future release,  Instead, use the \c MacStateValue
      * TracedValue.
      */
-    TracedCallback<LrWpanMacState, LrWpanMacState> m_macStateLogger;
+    TracedCallback<MacState, MacState> m_macStateLogger;
 
     /**
      * The PHY associated with this MAC.
@@ -1134,7 +1136,7 @@
     /**
      * The current state of the MAC layer.
      */
-    TracedValue<LrWpanMacState> m_lrWpanMacState;
+    TracedValue<MacState> m_macState;
 
     /**
      * The current period of the incoming superframe.
@@ -1167,7 +1169,7 @@
     /**
      * The extended 64 address (IEEE EUI-64) used by this MAC.
      */
-    Mac64Address m_selfExt;
+    Mac64Address m_macExtendedAddress;
 
     /**
      * The transmit queue used by the MAC.
@@ -1322,6 +1324,7 @@
      */
     EventId m_scanEnergyEvent;
 };
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_MAC_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-header.cc ns-3.42/src/lr-wpan/model/lr-wpan-mac-header.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-header.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-header.cc	2024-05-29 15:29:46.976073300 -0700
@@ -22,6 +22,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_OBJECT_ENSURE_REGISTERED(LrWpanMacHeader);
 
@@ -746,4 +748,5 @@
     return i.GetDistanceFrom(start);
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-header.h ns-3.42/src/lr-wpan/model/lr-wpan-mac-header.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-header.h	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-header.h	2024-05-29 15:29:46.976073300 -0700
@@ -43,6 +43,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /**
  * \ingroup lr-wpan
@@ -449,6 +451,7 @@
 
 }; // LrWpanMacHeader
 
-}; // namespace ns3
+} // namespace lrwpan
+} // namespace ns3
 
 #endif /* LR_WPAN_MAC_HEADER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc ns-3.42/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc	2024-02-09 14:44:07.953790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc	2024-05-29 15:29:46.976073300 -0700
@@ -24,6 +24,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /***********************************************************
  *                Beacon MAC Payload
@@ -172,20 +174,15 @@
         size += 3; // (short address + Association Status)
         break;
     case DISASSOCIATION_NOTIF:
-        break;
     case DATA_REQ:
-        break;
     case PANID_CONFLICT:
-        break;
     case ORPHAN_NOTIF:
-        break;
     case BEACON_REQ:
         break;
     case COOR_REALIGN:
         size += 8;
         break;
     case GTS_REQ:
-        break;
     case CMD_RESERVED:
         break;
     }
@@ -208,13 +205,9 @@
         i.WriteU8(m_assocStatus);
         break;
     case DISASSOCIATION_NOTIF:
-        break;
     case DATA_REQ:
-        break;
     case PANID_CONFLICT:
-        break;
     case ORPHAN_NOTIF:
-        break;
     case BEACON_REQ:
         break;
     case COOR_REALIGN:
@@ -225,7 +218,6 @@
         i.WriteU8(m_logChPage);
         break;
     case GTS_REQ:
-        break;
     case CMD_RESERVED:
         break;
     }
@@ -247,13 +239,9 @@
         m_assocStatus = i.ReadU8();
         break;
     case DISASSOCIATION_NOTIF:
-        break;
     case DATA_REQ:
-        break;
     case PANID_CONFLICT:
-        break;
     case ORPHAN_NOTIF:
-        break;
     case BEACON_REQ:
         break;
     case COOR_REALIGN:
@@ -264,7 +252,6 @@
         m_logChPage = i.ReadU8();
         break;
     case GTS_REQ:
-        break;
     case CMD_RESERVED:
         break;
     }
@@ -292,13 +279,9 @@
            << "| Status Response | = " << m_assocStatus;
         break;
     case DISASSOCIATION_NOTIF:
-        break;
     case DATA_REQ:
-        break;
     case PANID_CONFLICT:
-        break;
     case ORPHAN_NOTIF:
-        break;
     case BEACON_REQ:
         break;
     case COOR_REALIGN:
@@ -309,9 +292,7 @@
            << "| Page Num.| = " << static_cast<uint32_t>(m_logChPage);
         break;
     case GTS_REQ:
-        break;
     case CMD_RESERVED:
-        break;
     default:
         break;
     }
@@ -448,4 +429,5 @@
     return m_panid;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-pl-headers.h ns-3.42/src/lr-wpan/model/lr-wpan-mac-pl-headers.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-pl-headers.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-pl-headers.h	2024-05-29 15:29:46.976073300 -0700
@@ -28,6 +28,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 /**
  * \ingroup lr-wpan
@@ -239,6 +241,7 @@
     uint8_t m_assocStatus;         //!< Association Status (Association Response Command)
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_MAC_PL_HEADERS_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-trailer.cc ns-3.42/src/lr-wpan/model/lr-wpan-mac-trailer.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-trailer.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-trailer.cc	2024-05-29 15:29:46.976073300 -0700
@@ -25,6 +25,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_OBJECT_ENSURE_REGISTERED(LrWpanMacTrailer);
 
@@ -159,4 +161,5 @@
     return accumulator;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-mac-trailer.h ns-3.42/src/lr-wpan/model/lr-wpan-mac-trailer.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-mac-trailer.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-mac-trailer.h	2024-05-29 15:29:46.976073300 -0700
@@ -30,6 +30,9 @@
 
 class Packet;
 
+namespace lrwpan
+{
+
 /**
  * \ingroup lr-wpan
  *
@@ -120,6 +123,7 @@
     bool m_calcFcs;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_MAC_TRAILER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-net-device.cc ns-3.42/src/lr-wpan/model/lr-wpan-net-device.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-net-device.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-net-device.cc	2024-05-29 15:29:46.976073300 -0700
@@ -35,9 +35,10 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanNetDevice");
-
 NS_OBJECT_ENSURE_REGISTERED(LrWpanNetDevice);
 
 TypeId
@@ -559,4 +560,5 @@
     return (streamIndex - stream);
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-net-device.h ns-3.42/src/lr-wpan/model/lr-wpan-net-device.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-net-device.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-net-device.h	2024-05-29 15:29:46.976073300 -0700
@@ -30,11 +30,15 @@
 namespace ns3
 {
 
-class LrWpanPhy;
-class LrWpanCsmaCa;
 class SpectrumChannel;
 class Node;
 
+namespace lrwpan
+{
+
+class LrWpanPhy;
+class LrWpanCsmaCa;
+
 /**
  * \ingroup lr-wpan
  *
@@ -316,6 +320,7 @@
     PseudoMacAddressMode_e m_pseudoMacMode;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_NET_DEVICE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-phy.cc ns-3.42/src/lr-wpan/model/lr-wpan-phy.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-phy.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-phy.cc	2024-05-29 15:29:46.976073300 -0700
@@ -45,9 +45,10 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanPhy");
-
 NS_OBJECT_ENSURE_REGISTERED(LrWpanPhy);
 
 /**
@@ -56,7 +57,7 @@
  * Bit rate is in kbit/s.  Symbol rate is in ksymbol/s.
  * The index follows LrWpanPhyOption (kb/s and ksymbol/s)
  */
-static const LrWpanPhyDataAndSymbolRates dataSymbolRates[IEEE_802_15_4_INVALID_PHY_OPTION]{
+static const PhyDataAndSymbolRates dataSymbolRates[IEEE_802_15_4_INVALID_PHY_OPTION]{
     {20.0, 20.0},
     {40.0, 40.0},
     {20.0, 20.0},
@@ -75,7 +76,7 @@
  * The PHR is 1 octet and it follows phySymbolsPerOctet in Table 23.
  * The index follows LrWpanPhyOption.
  */
-const LrWpanPhyPpduHeaderSymbolNumber ppduHeaderSymbolNumbers[IEEE_802_15_4_INVALID_PHY_OPTION]{
+const PhyPpduHeaderSymbolNumber ppduHeaderSymbolNumbers[IEEE_802_15_4_INVALID_PHY_OPTION]{
     {32.0, 8.0, 8.0},
     {32.0, 8.0, 8.0},
     {32.0, 8.0, 8.0},
@@ -88,47 +89,47 @@
 };
 
 std::ostream&
-operator<<(std::ostream& os, const LrWpanPhyEnumeration& state)
+operator<<(std::ostream& os, const PhyEnumeration& state)
 {
     switch (state)
     {
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_BUSY:
+    case PhyEnumeration::IEEE_802_15_4_PHY_BUSY:
         os << "BUSY";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_BUSY_RX:
+    case PhyEnumeration::IEEE_802_15_4_PHY_BUSY_RX:
         os << "BUSY_RX";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_BUSY_TX:
+    case PhyEnumeration::IEEE_802_15_4_PHY_BUSY_TX:
         os << "BUSY_TX";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_FORCE_TRX_OFF:
+    case PhyEnumeration::IEEE_802_15_4_PHY_FORCE_TRX_OFF:
         os << "FORCE_TRX_OFF";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_IDLE:
+    case PhyEnumeration::IEEE_802_15_4_PHY_IDLE:
         os << "IDLE";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_INVALID_PARAMETER:
+    case PhyEnumeration::IEEE_802_15_4_PHY_INVALID_PARAMETER:
         os << "INVALID_PARAMETER";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_RX_ON:
+    case PhyEnumeration::IEEE_802_15_4_PHY_RX_ON:
         os << "RX_ON";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS:
+    case PhyEnumeration::IEEE_802_15_4_PHY_SUCCESS:
         os << "SUCCESS";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_TRX_OFF:
+    case PhyEnumeration::IEEE_802_15_4_PHY_TRX_OFF:
         os << "TRX_OFF";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_TX_ON:
+    case PhyEnumeration::IEEE_802_15_4_PHY_TX_ON:
         os << "TX_ON";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE:
+    case PhyEnumeration::IEEE_802_15_4_PHY_UNSUPPORTED_ATTRIBUTE:
         os << "UNSUPPORTED";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_READ_ONLY:
+    case PhyEnumeration::IEEE_802_15_4_PHY_READ_ONLY:
         os << "READ_ONLY";
         break;
-    case LrWpanPhyEnumeration::IEEE_802_15_4_PHY_UNSPECIFIED:
+    case PhyEnumeration::IEEE_802_15_4_PHY_UNSPECIFIED:
         os << "UNSPECIFIED";
         break;
     }
@@ -136,9 +137,9 @@
 };
 
 std::ostream&
-operator<<(std::ostream& os, const TracedValue<LrWpanPhyEnumeration>& state)
+operator<<(std::ostream& os, const TracedValue<PhyEnumeration>& state)
 {
-    LrWpanPhyEnumeration s = state;
+    PhyEnumeration s = state;
     return os << s;
 };
 
@@ -279,16 +280,14 @@
 
     m_random = nullptr;
     m_pdDataIndicationCallback = MakeNullCallback<void, uint32_t, Ptr<Packet>, uint8_t>();
-    m_pdDataConfirmCallback = MakeNullCallback<void, LrWpanPhyEnumeration>();
-    m_plmeCcaConfirmCallback = MakeNullCallback<void, LrWpanPhyEnumeration>();
-    m_plmeEdConfirmCallback = MakeNullCallback<void, LrWpanPhyEnumeration, uint8_t>();
-    m_plmeGetAttributeConfirmCallback = MakeNullCallback<void,
-                                                         LrWpanPhyEnumeration,
-                                                         LrWpanPibAttributeIdentifier,
-                                                         Ptr<LrWpanPhyPibAttributes>>();
-    m_plmeSetTRXStateConfirmCallback = MakeNullCallback<void, LrWpanPhyEnumeration>();
+    m_pdDataConfirmCallback = MakeNullCallback<void, PhyEnumeration>();
+    m_plmeCcaConfirmCallback = MakeNullCallback<void, PhyEnumeration>();
+    m_plmeEdConfirmCallback = MakeNullCallback<void, PhyEnumeration, uint8_t>();
+    m_plmeGetAttributeConfirmCallback =
+        MakeNullCallback<void, PhyEnumeration, PhyPibAttributeIdentifier, Ptr<PhyPibAttributes>>();
+    m_plmeSetTRXStateConfirmCallback = MakeNullCallback<void, PhyEnumeration>();
     m_plmeSetAttributeConfirmCallback =
-        MakeNullCallback<void, LrWpanPhyEnumeration, LrWpanPibAttributeIdentifier>();
+        MakeNullCallback<void, PhyEnumeration, PhyPibAttributeIdentifier>();
 
     SpectrumPhy::DoDispose();
 }
@@ -404,7 +403,7 @@
     NS_ASSERT(p);
 
     // Prevent PHY from receiving another packet while switching the transceiver state.
-    if (m_trxState == IEEE_802_15_4_PHY_RX_ON && !m_setTRXState.IsRunning())
+    if (m_trxState == IEEE_802_15_4_PHY_RX_ON && !m_setTRXState.IsPending())
     {
         // The specification doesn't seem to refer to BUSY_RX, but vendor
         // data sheets suggest that this is a substate of the RX_ON state
@@ -647,7 +646,7 @@
     }
 
     // Prevent PHY from sending a packet while switching the transceiver state.
-    if (!m_setTRXState.IsRunning())
+    if (!m_setTRXState.IsPending())
     {
         if (m_trxState == IEEE_802_15_4_PHY_TX_ON)
         {
@@ -755,7 +754,7 @@
     }
     else
     {
-        LrWpanPhyEnumeration result = m_trxState;
+        PhyEnumeration result = m_trxState;
         if (m_trxState == IEEE_802_15_4_PHY_BUSY_TX)
         {
             result = IEEE_802_15_4_PHY_TX_ON;
@@ -769,11 +768,11 @@
 }
 
 void
-LrWpanPhy::PlmeGetAttributeRequest(LrWpanPibAttributeIdentifier id)
+LrWpanPhy::PlmeGetAttributeRequest(PhyPibAttributeIdentifier id)
 {
     NS_LOG_FUNCTION(this << id);
-    LrWpanPhyEnumeration status = IEEE_802_15_4_PHY_SUCCESS;
-    Ptr<LrWpanPhyPibAttributes> attributes = Create<LrWpanPhyPibAttributes>();
+    PhyEnumeration status = IEEE_802_15_4_PHY_SUCCESS;
+    Ptr<PhyPibAttributes> attributes = Create<PhyPibAttributes>();
 
     switch (id)
     {
@@ -802,7 +801,7 @@
 
 // Section 6.2.2.7.3
 void
-LrWpanPhy::PlmeSetTRXStateRequest(LrWpanPhyEnumeration state)
+LrWpanPhy::PlmeSetTRXStateRequest(PhyEnumeration state)
 {
     NS_LOG_FUNCTION(this << state);
 
@@ -1031,12 +1030,11 @@
 }
 
 void
-LrWpanPhy::PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier id,
-                                   Ptr<LrWpanPhyPibAttributes> attribute)
+LrWpanPhy::PlmeSetAttributeRequest(PhyPibAttributeIdentifier id, Ptr<PhyPibAttributes> attribute)
 {
     NS_LOG_FUNCTION(this << id << attribute);
     NS_ASSERT(attribute);
-    LrWpanPhyEnumeration status = IEEE_802_15_4_PHY_SUCCESS;
+    PhyEnumeration status = IEEE_802_15_4_PHY_SUCCESS;
 
     switch (id)
     {
@@ -1354,7 +1352,7 @@
 }
 
 void
-LrWpanPhy::ChangeTrxState(LrWpanPhyEnumeration newState)
+LrWpanPhy::ChangeTrxState(PhyEnumeration newState)
 {
     NS_LOG_LOGIC(this << " state: " << m_trxState << " -> " << newState);
 
@@ -1371,7 +1369,7 @@
 }
 
 void
-LrWpanPhy::CancelEd(LrWpanPhyEnumeration state)
+LrWpanPhy::CancelEd(PhyEnumeration state)
 {
     NS_LOG_FUNCTION(this);
     NS_ASSERT(state == IEEE_802_15_4_PHY_TRX_OFF || state == IEEE_802_15_4_PHY_TX_ON);
@@ -1426,7 +1424,7 @@
 LrWpanPhy::EndCca()
 {
     NS_LOG_FUNCTION(this);
-    LrWpanPhyEnumeration sensedChannelState = IEEE_802_15_4_PHY_UNSPECIFIED;
+    PhyEnumeration sensedChannelState = IEEE_802_15_4_PHY_UNSPECIFIED;
 
     // Update peak power.
     double power = LrWpanSpectrumValueHelper::TotalAvgPower(m_signal->GetSignalPsd(),
@@ -1549,7 +1547,7 @@
     {
         // Only change the state immediately, if the transceiver is not already
         // switching the state.
-        if (!m_setTRXState.IsRunning())
+        if (!m_setTRXState.IsPending())
         {
             NS_LOG_LOGIC("Apply pending state change to " << m_trxStatePending);
             ChangeTrxState(m_trxStatePending);
@@ -1631,7 +1629,7 @@
 }
 
 void
-LrWpanPhy::SetPhyOption(LrWpanPhyOption phyOption)
+LrWpanPhy::SetPhyOption(PhyOption phyOption)
 {
     NS_LOG_FUNCTION(this);
 
@@ -1786,7 +1784,7 @@
     return WToDbm(m_rxSensitivity);
 }
 
-LrWpanPhyOption
+PhyOption
 LrWpanPhy::GetMyPhyOption()
 {
     NS_LOG_FUNCTION(this);
@@ -1910,4 +1908,5 @@
     m_postReceptionErrorModel = em;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-phy.h ns-3.42/src/lr-wpan/model/lr-wpan-phy.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-phy.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-phy.h	2024-05-29 15:29:46.976073300 -0700
@@ -35,8 +35,6 @@
 
 class Packet;
 class SpectrumValue;
-class LrWpanErrorModel;
-struct LrWpanSpectrumSignalParameters;
 class MobilityModel;
 class SpectrumChannel;
 class SpectrumModel;
@@ -45,12 +43,18 @@
 class UniformRandomVariable;
 class ErrorModel;
 
+namespace lrwpan
+{
+
+class LrWpanErrorModel;
+struct LrWpanSpectrumSignalParameters;
+
 /**
  * \ingroup lr-wpan
  *
  * Helper structure to manage the power measurement during ED.
  */
-struct LrWpanEdPower
+struct EdPower
 {
     double averagePower;    //!< Average measured power
     Time lastUpdate;        //!< Last update time
@@ -63,7 +67,7 @@
  * This data structure provides the Bit rate and Symbol rate for a given channel
  * See IEEE802.15.4-2006 Table 1 and 2 in section 6.1.1 and 6.1.2
  */
-struct LrWpanPhyDataAndSymbolRates
+struct PhyDataAndSymbolRates
 {
     double bitRate;    //!< bit rate
     double symbolRate; //!< symbol rate
@@ -75,7 +79,7 @@
  * This data structure provides number of symbols for the PPDU headers: SHR and PHR
  * See IEEE802.15.4-2006 Figure 16, Table 19 and 20 in section 6.3
  */
-struct LrWpanPhyPpduHeaderSymbolNumber
+struct PhyPpduHeaderSymbolNumber
 {
     double shrPreamble; //!< Number of symbols for the SHR preamble
     double shrSfd;      //!< Number of symbols for the SHR SFD
@@ -87,7 +91,7 @@
  *
  * This Phy option will be used to index various Tables in IEEE802.15.4-2011
  */
-enum LrWpanPhyOption
+enum PhyOption
 {
     IEEE_802_15_4_868MHZ_BPSK,
     IEEE_802_15_4_915MHZ_BPSK,
@@ -107,7 +111,7 @@
  * IEEE802.15.4-2006 PHY Emumerations Table 18
  * in section 6.2.3
  */
-enum LrWpanPhyEnumeration
+enum PhyEnumeration
 {
     IEEE_802_15_4_PHY_BUSY = 0x00,
     IEEE_802_15_4_PHY_BUSY_RX = 0x01,
@@ -125,33 +129,33 @@
 };
 
 /**
- *  Overloaded operator to print the value of a LrWpanPhyEnumeration.
+ *  Overloaded operator to print the value of a PhyEnumeration.
  *
  *  \param os The output stream
  *  \param state The text value of the PHY state
  *  \return The output stream with text value of the PHY state
  */
-std::ostream& operator<<(std::ostream& os, const LrWpanPhyEnumeration& state);
+std::ostream& operator<<(std::ostream& os, const PhyEnumeration& state);
 
 /**
- *  Overloaded operator to print the value of a TracedValue<LrWpanPhyEnumeration>.
+ *  Overloaded operator to print the value of a TracedValue<PhyEnumeration>.
  *
  *  \param os The output stream
  *  \param state The text value of the PHY state
  *  \return The output stream with text value of the PHY state
  */
-std::ostream& operator<<(std::ostream& os, const TracedValue<LrWpanPhyEnumeration>& state);
+std::ostream& operator<<(std::ostream& os, const TracedValue<PhyEnumeration>& state);
 
 namespace TracedValueCallback
 {
 /**
  * \ingroup lr-wpan
- * TracedValue callback signature for LrWpanPhyEnumeration.
+ * TracedValue callback signature for PhyEnumeration.
  *
  * \param [in] oldValue original value of the traced variable
  * \param [in] newValue new value of the traced variable
  */
-typedef void (*LrWpanPhyEnumeration)(LrWpanPhyEnumeration oldValue, LrWpanPhyEnumeration newValue);
+typedef void (*PhyEnumeration)(PhyEnumeration oldValue, PhyEnumeration newValue);
 } // namespace TracedValueCallback
 
 /**
@@ -159,7 +163,7 @@
  *
  * IEEE802.15.4-2006 PHY PIB Attribute Identifiers Table 23 in section 6.4.2
  */
-enum LrWpanPibAttributeIdentifier
+enum PhyPibAttributeIdentifier
 {
     phyCurrentChannel = 0x00,
     phyChannelsSupported = 0x01,
@@ -176,7 +180,7 @@
  *
  * IEEE802.15.4-2006 PHY PIB Attributes Table 23 in section 6.4.2
  */
-struct LrWpanPhyPibAttributes : public SimpleRefCount<LrWpanPhyPibAttributes>
+struct PhyPibAttributes : public SimpleRefCount<PhyPibAttributes>
 {
     uint8_t phyCurrentChannel;         //!< The RF channel to use
     uint32_t phyChannelsSupported[32]; //!< BitField representing the available channels supported
@@ -208,7 +212,7 @@
  *
  * @param status the status to be transmitted
  */
-typedef Callback<void, LrWpanPhyEnumeration> PdDataConfirmCallback;
+typedef Callback<void, PhyEnumeration> PdDataConfirmCallback;
 
 /**
  * \ingroup lr-wpan
@@ -217,7 +221,7 @@
  *
  * @param status the status of CCA
  */
-typedef Callback<void, LrWpanPhyEnumeration> PlmeCcaConfirmCallback;
+typedef Callback<void, PhyEnumeration> PlmeCcaConfirmCallback;
 
 /**
  * \ingroup lr-wpan
@@ -227,7 +231,7 @@
  * @param status the status of ED
  * @param energyLevel the energy level of ED
  */
-typedef Callback<void, LrWpanPhyEnumeration, uint8_t> PlmeEdConfirmCallback;
+typedef Callback<void, PhyEnumeration, uint8_t> PlmeEdConfirmCallback;
 
 /**
  * \ingroup lr-wpan
@@ -238,10 +242,7 @@
  * @param id the identifier of attribute
  * @param attribute the pointer to attribute struct
  */
-typedef Callback<void,
-                 LrWpanPhyEnumeration,
-                 LrWpanPibAttributeIdentifier,
-                 Ptr<LrWpanPhyPibAttributes>>
+typedef Callback<void, PhyEnumeration, PhyPibAttributeIdentifier, Ptr<PhyPibAttributes>>
     PlmeGetAttributeConfirmCallback;
 
 /**
@@ -251,7 +252,7 @@
  *
  * @param status the status of PlmeSetTRXStateRequest
  */
-typedef Callback<void, LrWpanPhyEnumeration> PlmeSetTRXStateConfirmCallback;
+typedef Callback<void, PhyEnumeration> PlmeSetTRXStateConfirmCallback;
 
 /**
  * \ingroup lr-wpan
@@ -261,8 +262,7 @@
  * @param status the status of PlmeSetAttributeRequest
  * @param id the identifier of attribute
  */
-typedef Callback<void, LrWpanPhyEnumeration, LrWpanPibAttributeIdentifier>
-    PlmeSetAttributeConfirmCallback;
+typedef Callback<void, PhyEnumeration, PhyPibAttributeIdentifier> PlmeSetAttributeConfirmCallback;
 
 /**
  * \ingroup lr-wpan
@@ -337,7 +337,7 @@
      *
      * @param phyOption The phy modulation option used by the model.
      */
-    void SetPhyOption(LrWpanPhyOption phyOption);
+    void SetPhyOption(PhyOption phyOption);
 
     /**
      * Set the receiver power sensitivity used by this device in dBm.
@@ -400,7 +400,7 @@
      * Get attributes per definition from Table 23 in section 6.4.2
      * \param id the attributed identifier
      */
-    void PlmeGetAttributeRequest(LrWpanPibAttributeIdentifier id);
+    void PlmeGetAttributeRequest(PhyPibAttributeIdentifier id);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.7
@@ -408,7 +408,7 @@
      * Set PHY state
      * \param state in RX_ON,TRX_OFF,FORCE_TRX_OFF,TX_ON
      */
-    void PlmeSetTRXStateRequest(LrWpanPhyEnumeration state);
+    void PlmeSetTRXStateRequest(PhyEnumeration state);
 
     /**
      * IEEE 802.15.4-2006 section 6.2.2.9
@@ -417,8 +417,7 @@
      * \param id the attributed identifier
      * \param attribute the attribute value
      */
-    void PlmeSetAttributeRequest(LrWpanPibAttributeIdentifier id,
-                                 Ptr<LrWpanPhyPibAttributes> attribute);
+    void PlmeSetAttributeRequest(PhyPibAttributeIdentifier id, Ptr<PhyPibAttributes> attribute);
 
     /**
      * set the callback for the end of a RX, as part of the
@@ -569,8 +568,8 @@
      * be removed in a future release.
      */
     typedef void (*StateTracedCallback)(Time time,
-                                        LrWpanPhyEnumeration oldState,
-                                        LrWpanPhyEnumeration newState);
+                                        PhyEnumeration oldState,
+                                        PhyEnumeration newState);
 
   private:
     /**
@@ -587,7 +586,7 @@
      *
      * \param newState the new state
      */
-    void ChangeTrxState(LrWpanPhyEnumeration newState);
+    void ChangeTrxState(PhyEnumeration newState);
 
     /**
      * Get the currently configured PHY option.
@@ -595,11 +594,11 @@
      *
      * \return the PHY option
      */
-    LrWpanPhyOption GetMyPhyOption();
+    PhyOption GetMyPhyOption();
 
     /**
      * Finish the transmission of a frame. This is called at the end of a frame
-     * transmission, applying possibly pending PHY state changes and fireing the
+     * transmission, applying possibly pending PHY state changes and firing the
      * appropriate trace sources and confirm callbacks to the MAC.
      */
     void EndTx();
@@ -612,7 +611,7 @@
 
     /**
      * Finish the reception of a frame. This is called at the end of a frame
-     * reception, applying possibly pending PHY state changes and fireing the
+     * reception, applying possibly pending PHY state changes and firing the
      * appropriate trace sources and indication callbacks to the MAC. A frame
      * destroyed by noise/interference is dropped here, but not during reception.
      * This method is also called for every packet which only contributes to
@@ -629,7 +628,7 @@
      *
      * \param state the new state which is the cause for canceling ED
      */
-    void CancelEd(LrWpanPhyEnumeration state);
+    void CancelEd(PhyEnumeration state);
 
     /**
      * Called at the end of the ED procedure. The average energy detected is
@@ -746,11 +745,11 @@
      * The trace source fired when the phy layer changes the transceiver state.
      *
      * \see class CallBackTraceSource
-     * \deprecated The LrWpanPhyEnumeration state is now accessible as the
+     * \deprecated The PhyEnumeration state is now accessible as the
      * TracedValue \c TrxStateValue.  This TracedCallback will
      * be removed in a future release.
      */
-    TracedCallback<Time, LrWpanPhyEnumeration, LrWpanPhyEnumeration> m_trxStateLogger;
+    TracedCallback<Time, PhyEnumeration, PhyEnumeration> m_trxStateLogger;
 
     /**
      * Calculates the nominal transmit power of the device in decibels relative to 1 mW
@@ -824,19 +823,19 @@
     /**
      * The current PHY PIB attributes.
      */
-    LrWpanPhyPibAttributes m_phyPIBAttributes;
+    PhyPibAttributes m_phyPIBAttributes;
 
     // State variables
     /**
      * The current transceiver state.
      */
-    TracedValue<LrWpanPhyEnumeration> m_trxState;
+    TracedValue<PhyEnumeration> m_trxState;
 
     /**
      * The next pending state to applied after the current action of the PHY is
      * completed.
      */
-    LrWpanPhyEnumeration m_trxStatePending;
+    PhyEnumeration m_trxStatePending;
 
     // Callbacks
     /**
@@ -884,12 +883,12 @@
     /**
      * The currently configured PHY type.
      */
-    LrWpanPhyOption m_phyOption;
+    PhyOption m_phyOption;
 
     /**
      * Helper value for tracking the average power during ED.
      */
-    LrWpanEdPower m_edPower;
+    EdPower m_edPower;
 
     /**
      * Helper value for the peak power value during CCA.
@@ -962,6 +961,7 @@
     Ptr<ErrorModel> m_postReceptionErrorModel; //!< Error model for receive packet events
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_PHY_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.cc ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.cc	2024-05-29 15:29:46.976073300 -0700
@@ -23,6 +23,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanSpectrumSignalParameters");
 
@@ -46,4 +48,5 @@
     return Create<LrWpanSpectrumSignalParameters>(*this);
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.h ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-signal-parameters.h	2024-05-29 15:29:46.976073300 -0700
@@ -27,6 +27,9 @@
 
 class PacketBurst;
 
+namespace lrwpan
+{
+
 /**
  * \ingroup lr-wpan
  *
@@ -53,6 +56,7 @@
     Ptr<PacketBurst> packetBurst;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /* LR_WPAN_SPECTRUM_SIGNAL_PARAMETERS_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc
--- ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-value-helper.cc	2024-05-29 15:29:46.976073300 -0700
@@ -25,6 +25,8 @@
 
 namespace ns3
 {
+namespace lrwpan
+{
 
 NS_LOG_COMPONENT_DEFINE("LrWpanSpectrumValueHelper");
 
@@ -152,4 +154,5 @@
     return totalAvgPower;
 }
 
+} // namespace lrwpan
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h
--- ns-3.41/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/model/lr-wpan-spectrum-value-helper.h	2024-05-29 15:29:46.976073300 -0700
@@ -26,6 +26,9 @@
 
 class SpectrumValue;
 
+namespace lrwpan
+{
+
 /**
  * \ingroup lr-wpan
  *
@@ -76,6 +79,7 @@
     double m_noiseFactor;
 };
 
+} // namespace lrwpan
 } // namespace ns3
 
 #endif /*  LR_WPAN_SPECTRUM_VALUE_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-ack-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-ack-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-ack-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-ack-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -37,6 +37,7 @@
 #include <string>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-ack-test");
 
@@ -336,19 +337,19 @@
 };
 
 LrWpanAckTestSuite::LrWpanAckTestSuite()
-    : TestSuite("lr-wpan-ack", UNIT)
+    : TestSuite("lr-wpan-ack", Type::UNIT)
 {
     AddTestCase(new LrWpanAckTestCase("short-unicast", LrWpanAckTestCase::SHORT_ADDRESS_UNICAST),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new LrWpanAckTestCase("short-multicast", LrWpanAckTestCase::SHORT_ADDRESS_MULTICAST),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LrWpanAckTestCase("short-broadcast", LrWpanAckTestCase::SHORT_ADDRESS_BROADCAST),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LrWpanAckTestCase("extended-unicast", LrWpanAckTestCase::EXTENDED_ADDRESS_UNICAST),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 static LrWpanAckTestSuite g_lrWpanAckTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-cca-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-cca-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-cca-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-cca-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -33,6 +33,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-clear-channel-assessment-test");
 
@@ -56,7 +57,7 @@
      */
     static void PlmeCcaConfirm(LrWpanCcaTestCase* testcase,
                                Ptr<LrWpanNetDevice> device,
-                               LrWpanPhyEnumeration status);
+                               PhyEnumeration status);
     /**
      * \brief Function called when PhyTxBegin is hit.
      * \param testcase The TestCase.
@@ -107,7 +108,7 @@
 
     void DoRun() override;
 
-    LrWpanPhyEnumeration m_status; //!< PHY status.
+    PhyEnumeration m_status; //!< PHY status.
 };
 
 LrWpanCcaTestCase::LrWpanCcaTestCase()
@@ -119,7 +120,7 @@
 void
 LrWpanCcaTestCase::PlmeCcaConfirm(LrWpanCcaTestCase* testcase,
                                   Ptr<LrWpanNetDevice> device,
-                                  LrWpanPhyEnumeration status)
+                                  PhyEnumeration status)
 {
     std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(9) << "["
               << Simulator::Now().As(Time::S) << "] " << device->GetMac()->GetShortAddress()
@@ -364,9 +365,9 @@
 };
 
 LrWpanCcaTestSuite::LrWpanCcaTestSuite()
-    : TestSuite("lr-wpan-clear-channel-assessment", UNIT)
+    : TestSuite("lr-wpan-clear-channel-assessment", Type::UNIT)
 {
-    AddTestCase(new LrWpanCcaTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanCcaTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanCcaTestSuite g_lrWpanCcaTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-collision-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-collision-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-collision-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-collision-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -28,6 +28,7 @@
 #include <ns3/test.h>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-collision-test");
 
@@ -225,9 +226,9 @@
 };
 
 LrWpanCollisionTestSuite::LrWpanCollisionTestSuite()
-    : TestSuite("lr-wpan-collision", UNIT)
+    : TestSuite("lr-wpan-collision", Type::UNIT)
 {
-    AddTestCase(new LrWpanCollisionTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanCollisionTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanCollisionTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-ed-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-ed-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-ed-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-ed-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -32,6 +32,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-energy-detection-test");
 
@@ -54,10 +55,10 @@
      * \param status The PHY status.
      * \param level The ED level.
      */
-    void PlmeEdConfirm(LrWpanPhyEnumeration status, uint8_t level);
+    void PlmeEdConfirm(PhyEnumeration status, uint8_t level);
 
-    LrWpanPhyEnumeration m_status; //!< PHY status.
-    uint8_t m_level;               //!< ED level.
+    PhyEnumeration m_status; //!< PHY status.
+    uint8_t m_level;         //!< ED level.
 };
 
 LrWpanEdTestCase::LrWpanEdTestCase()
@@ -68,7 +69,7 @@
 }
 
 void
-LrWpanEdTestCase::PlmeEdConfirm(LrWpanPhyEnumeration status, uint8_t level)
+LrWpanEdTestCase::PlmeEdConfirm(PhyEnumeration status, uint8_t level)
 {
     NS_LOG_UNCOND("Energy Detection completed with status "
                   << LrWpanHelper::LrWpanPhyEnumerationPrinter(status) << " and energy level "
@@ -168,7 +169,7 @@
     NS_TEST_EXPECT_MSG_EQ(m_status, IEEE_802_15_4_PHY_SUCCESS, "ED status SUCCESS (as expected)");
     NS_TEST_EXPECT_MSG_EQ(m_level, 0, "ED reported signal level 0 (as expected)");
 
-    // Configure the RX Power to be -106.58 dBm, i.e. exectly to receiver sensitivity.
+    // Configure the RX Power to be -106.58 dBm, i.e. exactly to receiver sensitivity.
     propModel->SetRss(-106.58);
 
     m_status = IEEE_802_15_4_PHY_UNSPECIFIED;
@@ -266,9 +267,9 @@
 };
 
 LrWpanEdTestSuite::LrWpanEdTestSuite()
-    : TestSuite("lr-wpan-energy-detection", UNIT)
+    : TestSuite("lr-wpan-energy-detection", Type::UNIT)
 {
-    AddTestCase(new LrWpanEdTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanEdTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanEdTestSuite g_lrWpanEdTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-error-model-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-error-model-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-error-model-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-error-model-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -33,6 +33,7 @@
 #include <ns3/test.h>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-error-model-test");
 
@@ -207,10 +208,10 @@
 };
 
 LrWpanErrorModelTestSuite::LrWpanErrorModelTestSuite()
-    : TestSuite("lr-wpan-error-model", UNIT)
+    : TestSuite("lr-wpan-error-model", Type::UNIT)
 {
-    AddTestCase(new LrWpanErrorModelTestCase, TestCase::QUICK);
-    AddTestCase(new LrWpanErrorDistanceTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanErrorModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new LrWpanErrorDistanceTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanErrorModelTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-ifs-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-ifs-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-ifs-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-ifs-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -33,6 +33,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-ifs-test");
 
@@ -418,9 +419,9 @@
 };
 
 LrWpanIfsTestSuite::LrWpanIfsTestSuite()
-    : TestSuite("lr-wpan-ifs-test", UNIT)
+    : TestSuite("lr-wpan-ifs-test", Type::UNIT)
 {
-    AddTestCase(new LrWpanDataIfsTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanDataIfsTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanIfsTestSuite lrWpanIfsTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-mac-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-mac-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-mac-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-mac-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -30,6 +30,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-mac-test");
 
@@ -66,8 +67,8 @@
      */
     void StateChangeNotificationDev0(std::string context,
                                      Time now,
-                                     LrWpanPhyEnumeration oldState,
-                                     LrWpanPhyEnumeration newState);
+                                     PhyEnumeration oldState,
+                                     PhyEnumeration newState);
     /**
      * Function called when a the PHY state changes in Dev2 [00:03]
      * \param context context
@@ -77,12 +78,12 @@
      */
     void StateChangeNotificationDev2(std::string context,
                                      Time now,
-                                     LrWpanPhyEnumeration oldState,
-                                     LrWpanPhyEnumeration newState);
+                                     PhyEnumeration oldState,
+                                     PhyEnumeration newState);
 
     void DoRun() override;
 
-    LrWpanPhyEnumeration m_dev0State; //!< Stores the PHY state of device 0 [00:01]
+    PhyEnumeration m_dev0State; //!< Stores the PHY state of device 0 [00:01]
 };
 
 TestRxOffWhenIdleAfterCsmaFailure::TestRxOffWhenIdleAfterCsmaFailure()
@@ -103,11 +104,11 @@
 void
 TestRxOffWhenIdleAfterCsmaFailure::DataConfirm(McpsDataConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         NS_LOG_DEBUG("LrWpanMcpsDataConfirmStatus = Success");
     }
-    else if (params.m_status == LrWpanMacStatus::CHANNEL_ACCESS_FAILURE)
+    else if (params.m_status == MacStatus::CHANNEL_ACCESS_FAILURE)
     {
         NS_LOG_DEBUG("LrWpanMcpsDataConfirmStatus =  Channel Access Failure");
     }
@@ -116,8 +117,8 @@
 void
 TestRxOffWhenIdleAfterCsmaFailure::StateChangeNotificationDev0(std::string context,
                                                                Time now,
-                                                               LrWpanPhyEnumeration oldState,
-                                                               LrWpanPhyEnumeration newState)
+                                                               PhyEnumeration oldState,
+                                                               PhyEnumeration newState)
 {
     NS_LOG_DEBUG(Simulator::Now().As(Time::S)
                  << context << "PHY state change at " << now.As(Time::S) << " from "
@@ -130,8 +131,8 @@
 void
 TestRxOffWhenIdleAfterCsmaFailure::StateChangeNotificationDev2(std::string context,
                                                                Time now,
-                                                               LrWpanPhyEnumeration oldState,
-                                                               LrWpanPhyEnumeration newState)
+                                                               PhyEnumeration oldState,
+                                                               PhyEnumeration newState)
 {
     NS_LOG_DEBUG(Simulator::Now().As(Time::S)
                  << context << "PHY state change at " << now.As(Time::S) << " from "
@@ -283,7 +284,7 @@
     Simulator::Run();
 
     NS_TEST_EXPECT_MSG_EQ(m_dev0State,
-                          LrWpanPhyEnumeration::IEEE_802_15_4_PHY_TRX_OFF,
+                          PhyEnumeration::IEEE_802_15_4_PHY_TRX_OFF,
                           "Error, dev0 [00:01] PHY should be in TRX_OFF after CSMA failure");
 
     Simulator::Destroy();
@@ -336,7 +337,7 @@
 void
 TestActiveScanPanDescriptors::ScanConfirm(MlmeScanConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         m_panDescriptorList = params.m_panDescList;
     }
@@ -455,9 +456,9 @@
     // PAN coordinator N2 (PAN 7) is set to channel 14 in non-beacon mode but answer to beacon
     // requests. The second coordinator includes a beacon payload of 25 bytes using the
     // MLME-SET.request primitive.
-    Ptr<LrWpanMacPibAttributes> pibAttribute = Create<LrWpanMacPibAttributes>();
+    Ptr<MacPibAttributes> pibAttribute = Create<MacPibAttributes>();
     pibAttribute->macBeaconPayload = Create<Packet>(25);
-    coord2NetDevice->GetMac()->MlmeSetRequest(LrWpanMacPibAttributeIdentifier::macBeaconPayload,
+    coord2NetDevice->GetMac()->MlmeSetRequest(MacPibAttributeIdentifier::macBeaconPayload,
                                               pibAttribute);
 
     MlmeStartRequestParams params2;
@@ -573,7 +574,7 @@
 void
 TestOrphanScan::ScanConfirm(MlmeScanConfirmParams params)
 {
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         m_orphanScanSuccess = true;
     }
@@ -723,11 +724,11 @@
 };
 
 LrWpanMacTestSuite::LrWpanMacTestSuite()
-    : TestSuite("lr-wpan-mac-test", UNIT)
+    : TestSuite("lr-wpan-mac-test", Type::UNIT)
 {
-    AddTestCase(new TestRxOffWhenIdleAfterCsmaFailure, TestCase::QUICK);
-    AddTestCase(new TestActiveScanPanDescriptors, TestCase::QUICK);
-    AddTestCase(new TestOrphanScan, TestCase::QUICK);
+    AddTestCase(new TestRxOffWhenIdleAfterCsmaFailure, TestCase::Duration::QUICK);
+    AddTestCase(new TestActiveScanPanDescriptors, TestCase::Duration::QUICK);
+    AddTestCase(new TestOrphanScan, TestCase::Duration::QUICK);
 }
 
 static LrWpanMacTestSuite g_lrWpanMacTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-packet-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-packet-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-packet-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-packet-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -27,6 +27,7 @@
 #include <vector>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-packet-test");
 
@@ -120,9 +121,9 @@
 };
 
 LrWpanPacketTestSuite::LrWpanPacketTestSuite()
-    : TestSuite("lr-wpan-packet", UNIT)
+    : TestSuite("lr-wpan-packet", Type::UNIT)
 {
-    AddTestCase(new LrWpanPacketTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanPacketTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanPacketTestSuite g_lrWpanPacketTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-pd-plme-sap-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-pd-plme-sap-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-pd-plme-sap-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-pd-plme-sap-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -25,6 +25,7 @@
 #include <ns3/test.h>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 /**
  * \ingroup lr-wpan-test
@@ -104,9 +105,9 @@
 };
 
 LrWpanPlmeAndPdInterfaceTestSuite::LrWpanPlmeAndPdInterfaceTestSuite()
-    : TestSuite("lr-wpan-plme-pd-sap", UNIT)
+    : TestSuite("lr-wpan-plme-pd-sap", Type::UNIT)
 {
-    AddTestCase(new LrWpanPlmeAndPdInterfaceTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanPlmeAndPdInterfaceTestCase, TestCase::Duration::QUICK);
 }
 
 // Do not forget to allocate an instance of this TestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-slotted-csmaca-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -29,6 +29,7 @@
 #include <ns3/single-model-spectrum-channel.h>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 NS_LOG_COMPONENT_DEFINE("lr-wpan-slotted-csma-test");
 
@@ -125,7 +126,7 @@
 {
     // In the case of transmissions with the acknowledgment flag activated, the transmission is only
     // successful if the acknowledgment was received.
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         NS_LOG_UNCOND(Simulator::Now().GetSeconds() << "s Transmission successfully sent");
         testcase->m_sentTime = Simulator::Now();
@@ -351,9 +352,9 @@
 };
 
 LrWpanSlottedCsmacaTestSuite::LrWpanSlottedCsmacaTestSuite()
-    : TestSuite("lr-wpan-slotted-csmaca", UNIT)
+    : TestSuite("lr-wpan-slotted-csmaca", Type::UNIT)
 {
-    AddTestCase(new LrWpanSlottedCsmacaTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanSlottedCsmacaTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanSlottedCsmacaTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lr-wpan/test/lr-wpan-spectrum-value-helper-test.cc ns-3.42/src/lr-wpan/test/lr-wpan-spectrum-value-helper-test.cc
--- ns-3.41/src/lr-wpan/test/lr-wpan-spectrum-value-helper-test.cc	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lr-wpan/test/lr-wpan-spectrum-value-helper-test.cc	2024-05-29 15:29:46.976073300 -0700
@@ -24,6 +24,7 @@
 #include <cmath>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 /**
  * \ingroup lr-wpan-test
@@ -85,9 +86,9 @@
 };
 
 LrWpanSpectrumValueHelperTestSuite::LrWpanSpectrumValueHelperTestSuite()
-    : TestSuite("lr-wpan-spectrum-value-helper", UNIT)
+    : TestSuite("lr-wpan-spectrum-value-helper", Type::UNIT)
 {
-    AddTestCase(new LrWpanSpectrumValueHelperTestCase, TestCase::QUICK);
+    AddTestCase(new LrWpanSpectrumValueHelperTestCase, TestCase::Duration::QUICK);
 }
 
 static LrWpanSpectrumValueHelperTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/doc/Makefile ns-3.42/src/lte/doc/Makefile
--- ns-3.41/src/lte/doc/Makefile	2024-02-09 14:44:07.957790400 -0800
+++ ns-3.42/src/lte/doc/Makefile	2024-05-29 15:29:46.976073300 -0700
@@ -223,7 +223,7 @@
 
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/doc/source/lte-design.rst ns-3.42/src/lte/doc/source/lte-design.rst
--- ns-3.41/src/lte/doc/source/lte-design.rst	2024-02-09 14:44:08.001790800 -0800
+++ ns-3.42/src/lte/doc/source/lte-design.rst	2024-05-29 15:29:47.000073200 -0700
@@ -288,7 +288,7 @@
 interfaces. The X2 interface is also modeled explicitly and it is described in more
 detail in section :ref:`sec-x2`
 
-The S1-MME, the S11 and the S5 interfaces are modeled using procotol data units sent
+The S1-MME, the S11 and the S5 interfaces are modeled using protocol data units sent
 over its respective links. These interfaces use the SCTP protocol as transport protocol
 but currently, the SCTP protocol is not modeled in the ns-3 simulator, so the
 UDP protocol is used instead of the SCTP protocol.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/doc/source/lte-references.rst ns-3.42/src/lte/doc/source/lte-references.rst
--- ns-3.41/src/lte/doc/source/lte-references.rst	2024-02-09 14:44:08.001790800 -0800
+++ ns-3.42/src/lte/doc/source/lte-references.rst	2024-05-29 15:29:47.000073200 -0700
@@ -4,8 +4,6 @@
 References
 =================================
 
-.. [TS25814] 3GPP TS 25.814 "Physical layer aspect for evolved Universal Terrestrial Radio Access"
-
 .. [TS29274] 3GPP TS 29.274 "GPRS Tunnelling Protocol for Control plane (GTPv2-C)"
 
 .. [TS36101] 3GPP TS 36.101 "E-UTRA User Equipment (UE) radio transmission and reception"
@@ -64,10 +62,6 @@
 .. [Baldo2009] N. Baldo and M. Miozzo, "Spectrum-aware Channel and PHY layer modeling for ns3",
    Proceedings of ICST NSTools 2009, Pisa, Italy
 
-.. [Piro2010] Giuseppe Piro, Luigi Alfredo Grieco, Gennaro Boggia, and Pietro Camarda,
-   "A Two-level Scheduling Algorithm for QoS Support in the Downlink of LTE Cellular Networks",
-   Proc. of European Wireless, EW2010, Lucca, Italy, Apr., 2010
-
 .. [Holtzman2000] J.M. Holtzman, "CDMA forward link waterfilling power control",
    in Proc. of IEEE VTC Spring, 2000.
 
@@ -105,12 +99,6 @@
    "Some results and insights on the performance gains of MIMO systems,"
    Selected Areas in Communications, IEEE Journal on , vol.21, no.5, pp. 839- 847, June 2003
 
-.. [Ikuno2010] J.C. Ikuno, M. Wrulich, M. Rupp, "System Level Simulation of LTE Networks,"
-   Vehicular Technology Conference (VTC 2010-Spring), 2010 IEEE 71st , vol., no., pp.1-5, 16-19 May 2010
-
-.. [Milos2012] J. Milos, "Performance Analysis Of PCFICH LTE Control Channel",
-   Proceedings of the 19th Conference STUDENT EEICT 2012, Brno, CZ, 2012.
-
 .. [FujitsuWhitePaper] "Enhancing LTE Cell-Edge Performance via PDCCH ICIC".
 
 .. [Bharucha2011] Z. Bharucha, G. Auer, T. Abe, N. Miki,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/helper/no-backhaul-epc-helper.cc ns-3.42/src/lte/helper/no-backhaul-epc-helper.cc
--- ns-3.41/src/lte/helper/no-backhaul-epc-helper.cc	2024-02-09 14:44:08.009791000 -0800
+++ ns-3.42/src/lte/helper/no-backhaul-epc-helper.cc	2024-05-29 15:29:47.004073400 -0700
@@ -105,7 +105,7 @@
     NetDeviceContainer tunDeviceContainer;
     tunDeviceContainer.Add(m_tunDevice);
     // the TUN device is on the same subnet as the UEs, so when a packet
-    // addressed to an UE arrives at the intenet to the WAN interface of
+    // addressed to an UE arrives at the internet to the WAN interface of
     // the PGW it will be forwarded to the TUN device.
     Ipv4InterfaceContainer tunDeviceIpv4IfContainer = AssignUeIpv4Address(tunDeviceContainer);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/cqa-ff-mac-scheduler.cc ns-3.42/src/lte/model/cqa-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/cqa-ff-mac-scheduler.cc	2024-02-09 14:44:08.013790800 -0800
+++ ns-3.42/src/lte/model/cqa-ff-mac-scheduler.cc	2024-05-29 15:29:47.008073300 -0700
@@ -47,10 +47,10 @@
 
 /// CGA Type 0 Allocation
 static const int CqaType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(CqaFfMacScheduler);
@@ -1571,8 +1571,8 @@
             lcActives = 1;
         }
         // NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
-        uint16_t RgbPerRnti = (*itMap).second.size();
-        double doubleRBgPerRnti = RgbPerRnti;
+        uint16_t RbgPerRnti = (*itMap).second.size();
+        double doubleRBgPerRnti = RbgPerRnti;
         double doubleRbgNum = numberOfRBGs;
         double rrRatio = doubleRBgPerRnti / doubleRbgNum;
         m_rnti_per_ratio.insert(std::pair<uint16_t, double>((*itMap).first, rrRatio));
@@ -1588,7 +1588,7 @@
         }
 
         newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi));
-        int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(0), RgbPerRnti * rbgSize) /
+        int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(0), RbgPerRnti * rbgSize) /
                       8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
         newDci.m_tbsSize.push_back(tbSize);
         newDci.m_resAlloc = 0; // only allocation type 0 at this stage
@@ -2596,7 +2596,7 @@
 CqaFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/cqa-ff-mac-scheduler.h ns-3.42/src/lte/model/cqa-ff-mac-scheduler.h
--- ns-3.41/src/lte/model/cqa-ff-mac-scheduler.h	2024-02-09 14:44:08.013790800 -0800
+++ ns-3.42/src/lte/model/cqa-ff-mac-scheduler.h	2024-05-29 15:29:47.008073300 -0700
@@ -213,7 +213,7 @@
     void DoSchedUlCqiInfoReq(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params);
 
     /**
-     * Get RGB Size
+     * Get RBG Size
      * \param dlbandwidth the DL bandwidth
      * \returns the size
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/epc-gtpc-header.cc ns-3.42/src/lte/model/epc-gtpc-header.cc
--- ns-3.41/src/lte/model/epc-gtpc-header.cc	2024-02-09 14:44:08.013790800 -0800
+++ ns-3.42/src/lte/model/epc-gtpc-header.cc	2024-05-29 15:29:47.008073300 -0700
@@ -497,6 +497,7 @@
     SetSequenceNumber(0);
     m_imsi = 0;
     m_uliEcgi = 0;
+    m_senderCpFteid = {};
 }
 
 GtpcCreateSessionRequestMessage::~GtpcCreateSessionRequestMessage()
@@ -658,6 +659,7 @@
     SetMessageType(GtpcHeader::CreateSessionResponse);
     SetSequenceNumber(0);
     m_cause = Cause_t::RESERVED;
+    m_senderCpFteid = {};
 }
 
 GtpcCreateSessionResponseMessage::~GtpcCreateSessionResponseMessage()
@@ -1206,6 +1208,7 @@
 {
     SetMessageType(GtpcHeader::DeleteBearerResponse);
     SetSequenceNumber(0);
+    m_cause = Cause_t::RESERVED;
 }
 
 GtpcDeleteBearerResponseMessage::~GtpcDeleteBearerResponseMessage()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/epc-gtpc-header.h ns-3.42/src/lte/model/epc-gtpc-header.h
--- ns-3.41/src/lte/model/epc-gtpc-header.h	2024-02-09 14:44:08.013790800 -0800
+++ ns-3.42/src/lte/model/epc-gtpc-header.h	2024-05-29 15:29:47.008073300 -0700
@@ -127,9 +127,9 @@
     /// FTEID structure
     struct Fteid_t
     {
-        InterfaceType_t interfaceType; //!< Interface type
-        Ipv4Address addr;              //!< IPv4 address
-        uint32_t teid;                 //!< TEID
+        InterfaceType_t interfaceType{}; //!< Interface type
+        Ipv4Address addr;                //!< IPv4 address
+        uint32_t teid;                   //!< TEID
     };
 
     /// Message Type enumeration
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/epc-mme-application.cc ns-3.42/src/lte/model/epc-mme-application.cc
--- ns-3.41/src/lte/model/epc-mme-application.cc	2024-02-09 14:44:08.013790800 -0800
+++ ns-3.42/src/lte/model/epc-mme-application.cc	2024-05-29 15:29:47.008073300 -0700
@@ -143,7 +143,7 @@
          bit != it->second->bearersToBeActivated.end();
          ++bit)
     {
-        GtpcCreateSessionRequestMessage::BearerContextToBeCreated bearerContext;
+        GtpcCreateSessionRequestMessage::BearerContextToBeCreated bearerContext{};
         bearerContext.epsBearerId = bit->bearerId;
         bearerContext.tft = bit->tft;
         bearerContext.bearerLevelQos = bit->bearer;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/eps-bearer.h ns-3.42/src/lte/model/eps-bearer.h
--- ns-3.41/src/lte/model/eps-bearer.h	2024-02-09 14:44:08.013790800 -0800
+++ ns-3.42/src/lte/model/eps-bearer.h	2024-05-29 15:29:47.008073300 -0700
@@ -243,34 +243,13 @@
 
   private:
     /**
-     * \brief Hashing QCI
-     *
-     * Qci are just uint8_t, so that's how we calculate the hash. Unfortunately,
-     * we have to provide this struct because gcc 4.9 would not compile otherwise.
-     */
-    struct QciHash
-    {
-        /**
-         * \brief Hash the QCI like a normal uint8_t
-         * \param s Qci to hash
-         * \return Hash of Qci
-         */
-        std::size_t operator()(const Qci& s) const noexcept
-        {
-            return std::hash<uint8_t>{}(s);
-        }
-    };
-
-    /**
      * \brief Map between QCI and requirements
      *
      * The tuple is formed by: resource type, priority, packet delay budget, packet error rate,
      *  default maximum data burst, default averaging window (0 when does not apply)
      */
-    typedef std::unordered_map<Qci,
-                               std::tuple<uint8_t, uint8_t, uint16_t, double, uint32_t, uint32_t>,
-                               QciHash>
-        BearerRequirementsMap;
+    using BearerRequirementsMap =
+        std::unordered_map<Qci, std::tuple<uint8_t, uint8_t, uint16_t, double, uint32_t, uint32_t>>;
 
     /**
      * \brief Get the resource type (NON-GBR, GBR, DC-GBR) of the selected QCI
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/fading-traces/fading_trace_generator.m ns-3.42/src/lte/model/fading-traces/fading_trace_generator.m
--- ns-3.41/src/lte/model/fading-traces/fading_trace_generator.m	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/fading-traces/fading_trace_generator.m	2024-05-29 15:29:47.112073700 -0700
@@ -31,7 +31,7 @@
 % when working with an FFT, the normalized frequency w is
 % w = 2 * pi * (f/fs) * t
 % hence the max normalized frequency w=2*pi corresponds to f = fs,
-% hence fs is also the max frequecy of our PowerSpectralDensity
+% hence fs is also the max frequency of our PowerSpectralDensity
 fs = 20e6;
 
 % sampling period must be determined corresponding to the sampling
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/fdbet-ff-mac-scheduler.cc ns-3.42/src/lte/model/fdbet-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/fdbet-ff-mac-scheduler.cc	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/fdbet-ff-mac-scheduler.cc	2024-05-29 15:29:47.112073700 -0700
@@ -39,10 +39,10 @@
 
 /// FdBetType0AllocationRbg array
 static const int FdBetType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(FdBetFfMacScheduler);
@@ -1037,7 +1037,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_p10CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1058,7 +1058,7 @@
                 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi((*itCqi).second));
             }
 
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             bytesTxed += tbSize;
@@ -2020,7 +2020,7 @@
 FdBetFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/fdbet-ff-mac-scheduler.h ns-3.42/src/lte/model/fdbet-ff-mac-scheduler.h
--- ns-3.41/src/lte/model/fdbet-ff-mac-scheduler.h	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/fdbet-ff-mac-scheduler.h	2024-05-29 15:29:47.112073700 -0700
@@ -192,7 +192,7 @@
 
     /**
      * Sched UL SR info request function
-     * \param params the Schedul UL SR info request parameters
+     * \param params the Schedule UL SR info request parameters
      */
     void DoSchedUlSrInfoReq(const FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/fdmt-ff-mac-scheduler.cc ns-3.42/src/lte/model/fdmt-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/fdmt-ff-mac-scheduler.cc	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/fdmt-ff-mac-scheduler.cc	2024-05-29 15:29:47.112073700 -0700
@@ -39,10 +39,10 @@
 
 /// FdMtType0AllocationRbg size array
 static const int FdMtType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(FdMtFfMacScheduler);
@@ -980,7 +980,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_a30CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1047,7 +1047,7 @@
         for (uint8_t j = 0; j < nLayer; j++)
         {
             newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
@@ -1959,7 +1959,7 @@
 FdMtFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/fdtbfq-ff-mac-scheduler.cc ns-3.42/src/lte/model/fdtbfq-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/fdtbfq-ff-mac-scheduler.cc	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/fdtbfq-ff-mac-scheduler.cc	2024-05-29 15:29:47.112073700 -0700
@@ -40,10 +40,10 @@
 
 /// FdTbfqType0AllocationRbg value array
 static const int FdTbfqType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(FdTbfqFfMacScheduler);
@@ -1373,7 +1373,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_a30CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1440,7 +1440,7 @@
         for (uint8_t j = 0; j < nLayer; j++)
         {
             newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
@@ -2381,7 +2381,7 @@
 FdTbfqFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/fdtbfq-ff-mac-scheduler.h ns-3.42/src/lte/model/fdtbfq-ff-mac-scheduler.h
--- ns-3.41/src/lte/model/fdtbfq-ff-mac-scheduler.h	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/fdtbfq-ff-mac-scheduler.h	2024-05-29 15:29:47.112073700 -0700
@@ -125,7 +125,7 @@
     friend class MemberSchedSapProvider<FdTbfqFfMacScheduler>;
 
     /**
-     * Transmisson mode config update function
+     * Transmission mode config update function
      * \param rnti the RNTI
      * \param txMode the transmit mode
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/ff-mac-common.h ns-3.42/src/lte/model/ff-mac-common.h
--- ns-3.41/src/lte/model/ff-mac-common.h	2024-02-09 14:44:08.181792000 -0800
+++ ns-3.42/src/lte/model/ff-mac-common.h	2024-05-29 15:29:47.112073700 -0700
@@ -405,11 +405,13 @@
  */
 struct SrConfig_s
 {
-    enum SetupRelease_e m_action
+    /// Actions
+    enum SetupRelease_e
     {
         setup
-    }; ///< action
+    };
 
+    SetupRelease_e m_action;            ///< action
     uint8_t m_schedInterval{UINT8_MAX}; ///< sched interval
     uint8_t m_dsrTransMax{UINT8_MAX};   ///< trans max
 };
@@ -419,11 +421,13 @@
  */
 struct CqiConfig_s
 {
-    enum SetupRelease_e m_action
+    /// Actions
+    enum SetupRelease_e
     {
         setup
-    }; ///< action
+    };
 
+    SetupRelease_e m_action;                 ///< CQI action
     uint16_t m_cqiSchedInterval{UINT16_MAX}; ///< CQI schedule interval
     uint8_t m_riSchedInterval{UINT8_MAX};    ///< RI schedule interval
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-common.cc ns-3.42/src/lte/model/lte-common.cc
--- ns-3.41/src/lte/model/lte-common.cc	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-common.cc	2024-05-29 15:29:47.112073700 -0700
@@ -206,23 +206,15 @@
     switch (txMode)
     {
     case 0: // Tx MODE 1: SISO
-        nLayer = 1;
-        break;
     case 1: // Tx MODE 2: MIMO Tx Diversity
         nLayer = 1;
         break;
     case 2: // Tx MODE 3: MIMO Spatial Multiplexity Open Loop
-        nLayer = 2;
-        break;
     case 3: // Tx MODE 4: MIMO Spatial Multiplexity Closed Loop
-        nLayer = 2;
-        break;
     case 4: // Tx MODE 5: MIMO Multi-User
         nLayer = 2;
         break;
     case 5: // Tx MODE 6: Closer loop single layer percoding
-        nLayer = 1;
-        break;
     case 6: // Tx MODE 7: Single antenna port 5
         nLayer = 1;
         break;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-enb-mac.cc ns-3.42/src/lte/model/lte-enb-mac.cc
--- ns-3.41/src/lte/model/lte-enb-mac.cc	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-enb-mac.cc	2024-05-29 15:29:47.116073600 -0700
@@ -771,7 +771,7 @@
 LteEnbMac::DoConfigureMac(uint16_t ulBandwidth, uint16_t dlBandwidth)
 {
     NS_LOG_FUNCTION(this << " ulBandwidth=" << ulBandwidth << " dlBandwidth=" << dlBandwidth);
-    FfMacCschedSapProvider::CschedCellConfigReqParameters params;
+    FfMacCschedSapProvider::CschedCellConfigReqParameters params{};
     // Configure the subset of parameters used by FfMacScheduler
     params.m_ulBandwidth = ulBandwidth;
     params.m_dlBandwidth = dlBandwidth;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-enb-mac.h ns-3.42/src/lte/model/lte-enb-mac.h
--- ns-3.41/src/lte/model/lte-enb-mac.h	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-enb-mac.h	2024-05-29 15:29:47.116073600 -0700
@@ -364,12 +364,12 @@
 
   private:
     /**
-     * \brief UL Info List ELements HARQ Feedback function
+     * \brief UL Info List Elements HARQ Feedback function
      * \param params UlInfoListElement_s
      */
     void DoUlInfoListElementHarqFeedback(UlInfoListElement_s params);
     /**
-     * \brief DL Info List ELements HARQ Feedback function
+     * \brief DL Info List Elements HARQ Feedback function
      * \param params DlInfoListElement_s
      */
     void DoDlInfoListElementHarqFeedback(DlInfoListElement_s params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-enb-phy.cc ns-3.42/src/lte/model/lte-enb-phy.cc
--- ns-3.41/src/lte/model/lte-enb-phy.cc	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-enb-phy.cc	2024-05-29 15:29:47.116073600 -0700
@@ -882,10 +882,10 @@
     m_dlBandwidth = dlBandwidth;
 
     static const int Type0AllocationRbg[4] = {
-        10,  // RGB size 1
-        26,  // RGB size 2
-        63,  // RGB size 3
-        110, // RGB size 4
+        10,  // RBG size 1
+        26,  // RBG size 2
+        63,  // RBG size 3
+        110, // RBG size 4
     };       // see table 7.1.6.1-1 of 36.213
     for (int i = 0; i < 4; i++)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-enb-rrc.cc ns-3.42/src/lte/model/lte-enb-rrc.cc
--- ns-3.41/src/lte/model/lte-enb-rrc.cc	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-enb-rrc.cc	2024-05-29 15:29:47.116073600 -0700
@@ -576,7 +576,7 @@
     rrcd.physicalConfigDedicated = m_physicalConfigDedicated;
 
     // populating RRCConnectionReconfiguration message as per 3GPP TS 36.331 version 9.2.0 Release 9
-    LteRrcSap::RrcConnectionReconfiguration msg;
+    LteRrcSap::RrcConnectionReconfiguration msg{};
     msg.haveMeasConfig = false;
     msg.haveMobilityControlInfo = false;
     msg.radioResourceConfigDedicated = rrcd;
@@ -1593,7 +1593,7 @@
 UeManager::BuildRrcConnectionReconfiguration()
 {
     NS_LOG_FUNCTION(this);
-    LteRrcSap::RrcConnectionReconfiguration msg;
+    LteRrcSap::RrcConnectionReconfiguration msg{};
     msg.rrcTransactionIdentifier = GetNewRrcTransactionIdentifier();
     msg.haveRadioResourceConfigDedicated = true;
     msg.radioResourceConfigDedicated = BuildRadioResourceConfigDedicated();
@@ -1715,8 +1715,6 @@
         break;
 
     case CONNECTION_SETUP:
-        break;
-
     case ATTACH_REQUEST:
         break;
 
@@ -1733,14 +1731,8 @@
     break;
 
     case CONNECTION_RECONFIGURATION:
-        break;
-
     case CONNECTION_REESTABLISHMENT:
-        break;
-
     case HANDOVER_LEAVING:
-        break;
-
     default:
         break;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-ffr-algorithm.cc ns-3.42/src/lte/model/lte-ffr-algorithm.cc
--- ns-3.41/src/lte/model/lte-ffr-algorithm.cc	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-ffr-algorithm.cc	2024-05-29 15:29:47.116073600 -0700
@@ -29,12 +29,12 @@
 
 NS_LOG_COMPONENT_DEFINE("LteFfrAlgorithm");
 
-/// Type 0 RGB allocation
+/// Type 0 RBG allocation
 static const int Type0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 3GPP TS 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(LteFfrAlgorithm);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-ffr-distributed-algorithm.h ns-3.42/src/lte/model/lte-ffr-distributed-algorithm.h
--- ns-3.41/src/lte/model/lte-ffr-distributed-algorithm.h	2024-02-09 14:44:08.185792200 -0800
+++ ns-3.42/src/lte/model/lte-ffr-distributed-algorithm.h	2024-05-29 15:29:47.116073600 -0700
@@ -96,16 +96,16 @@
      */
     void SetUplinkConfiguration(uint16_t cellId, uint8_t bandwidth);
     /**
-     * Initialize down link RGB maps function
+     * Initialize down link RBG maps function
      */
     void InitializeDownlinkRbgMaps();
     /**
-     * Initialize up link RGB maps function
+     * Initialize up link RBG maps function
      */
     void InitializeUplinkRbgMaps();
 
     /**
-     * Initialize up link RGB maps function
+     * Initialize up link RBG maps function
      *
      * \param rnti the RNTI
      * \param cellId the cell ID
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-rlc-am.cc ns-3.42/src/lte/model/lte-rlc-am.cc
--- ns-3.41/src/lte/model/lte-rlc-am.cc	2024-02-09 14:44:08.189792200 -0800
+++ ns-3.42/src/lte/model/lte-rlc-am.cc	2024-05-29 15:29:47.116073600 -0700
@@ -212,7 +212,7 @@
         return;
     }
 
-    if (m_statusPduRequested && !m_statusProhibitTimer.IsRunning())
+    if (m_statusPduRequested && !m_statusProhibitTimer.IsPending())
     {
         if (txOpParams.bytes < m_statusPduBufferSize)
         {
@@ -340,7 +340,7 @@
                         m_pollSn = m_vtS - 1;
                         NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
 
-                        if (!m_pollRetransmitTimer.IsRunning())
+                        if (!m_pollRetransmitTimer.IsPending())
                         {
                             NS_LOG_LOGIC("Start PollRetransmit timer");
 
@@ -728,7 +728,7 @@
         m_pollSn = m_vtS - 1;
         NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
 
-        if (!m_pollRetransmitTimer.IsRunning())
+        if (!m_pollRetransmitTimer.IsPending())
         {
             NS_LOG_LOGIC("Start PollRetransmit timer");
 
@@ -884,7 +884,7 @@
             m_statusPduRequested = true;
             m_statusPduBufferSize = 4;
 
-            if (!m_statusProhibitTimer.IsRunning())
+            if (!m_statusProhibitTimer.IsPending())
             {
                 DoReportBufferStatus();
             }
@@ -1018,7 +1018,7 @@
         //     - if VR(X) falls outside of the receiving window and VR(X) is not equal to VR(MR):
         //         - stop and reset t-Reordering;
 
-        if (m_reorderingTimer.IsRunning())
+        if (m_reorderingTimer.IsPending())
         {
             NS_LOG_LOGIC("Reordering timer is running");
             if ((m_vrX == m_vrR) || ((!IsInsideReceivingWindow(m_vrX)) && (m_vrX != m_vrMr)))
@@ -1035,7 +1035,7 @@
         //         - start t-Reordering;
         //         - set VR(X) to VR(H).
 
-        if (!m_reorderingTimer.IsRunning())
+        if (!m_reorderingTimer.IsPending())
         {
             NS_LOG_LOGIC("Reordering timer is not running");
             if (m_vrH > m_vrR)
@@ -1076,7 +1076,7 @@
 
             uint16_t seqNumberValue = sn.GetValue();
 
-            if (m_pollRetransmitTimer.IsRunning() && (seqNumberValue == m_pollSn.GetValue()))
+            if (m_pollRetransmitTimer.IsPending() && (seqNumberValue == m_pollSn.GetValue()))
             {
                 m_pollRetransmitTimer.Cancel();
             }
@@ -1665,7 +1665,7 @@
     r.retxQueueSize = m_retxBufferSize + m_txedBufferSize;
     r.retxQueueHolDelay = retxQueueHolDelay.GetMilliSeconds();
 
-    if (m_statusPduRequested && !m_statusProhibitTimer.IsRunning())
+    if (m_statusPduRequested && !m_statusProhibitTimer.IsPending())
     {
         r.statusPduSize = m_statusPduBufferSize;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-rlc-um.cc ns-3.42/src/lte/model/lte-rlc-um.cc
--- ns-3.41/src/lte/model/lte-rlc-um.cc	2024-02-09 14:44:08.281792900 -0800
+++ ns-3.42/src/lte/model/lte-rlc-um.cc	2024-05-29 15:29:47.120073600 -0700
@@ -357,7 +357,7 @@
             firstSegment = m_txBuffer.begin()->m_pdu->Copy();
             firstSegmentTime = m_txBuffer.begin()->m_waitingSince;
             m_txBufferSize -= firstSegment->GetSize();
-            m_txBuffer.erase(m_txBuffer.begin());
+            m_txBuffer.pop_front();
             NS_LOG_LOGIC("        txBufferSize = " << m_txBufferSize);
         }
     }
@@ -584,7 +584,7 @@
     //    - if VR(UX) <= VR(UR); or
     //    - if VR(UX) falls outside of the reordering window and VR(UX) is not equal to VR(UH)::
     //        - stop and reset t-Reordering;
-    if (m_reorderingTimer.IsRunning())
+    if (m_reorderingTimer.IsPending())
     {
         NS_LOG_LOGIC("Reordering timer is running");
 
@@ -600,7 +600,7 @@
     //    - if VR(UH) > VR(UR):
     //        - start t-Reordering;
     //        - set VR(UX) to VR(UH).
-    if (!m_reorderingTimer.IsRunning())
+    if (!m_reorderingTimer.IsPending())
     {
         NS_LOG_LOGIC("Reordering timer is not running");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-rlc-um.h ns-3.42/src/lte/model/lte-rlc-um.h
--- ns-3.41/src/lte/model/lte-rlc-um.h	2024-02-09 14:44:08.281792900 -0800
+++ ns-3.42/src/lte/model/lte-rlc-um.h	2024-05-29 15:29:47.120073600 -0700
@@ -25,6 +25,7 @@
 
 #include <ns3/event-id.h>
 
+#include <deque>
 #include <map>
 
 namespace ns3
@@ -121,7 +122,7 @@
         Time m_waitingSince; ///< Layer arrival time
     };
 
-    std::vector<TxPdu> m_txBuffer;              ///< Transmission buffer
+    std::deque<TxPdu> m_txBuffer;               ///< Transmission buffer
     std::map<uint16_t, Ptr<Packet>> m_rxBuffer; ///< Reception buffer
     std::vector<Ptr<Packet>> m_reasBuffer;      ///< Reassembling buffer
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-rrc-header.cc ns-3.42/src/lte/model/lte-rrc-header.cc
--- ns-3.41/src/lte/model/lte-rrc-header.cc	2024-02-09 14:44:08.321793000 -0800
+++ ns-3.42/src/lte/model/lte-rrc-header.cc	2024-05-29 15:29:47.120073600 -0700
@@ -3983,12 +3983,10 @@
             case 1:
                 // Deserialize measObjectUTRA
                 // ...
-                break;
 
             case 2:
                 // Deserialize measObjectGERAN
                 // ...
-                break;
 
             case 3:
                 // Deserialize measObjectCDMA2000
@@ -5878,7 +5876,7 @@
 LteRrcSap::RrcConnectionReconfiguration
 RrcConnectionReconfigurationHeader::GetMessage() const
 {
-    LteRrcSap::RrcConnectionReconfiguration msg;
+    LteRrcSap::RrcConnectionReconfiguration msg{};
 
     msg.rrcTransactionIdentifier = m_rrcTransactionIdentifier;
     msg.haveMeasConfig = m_haveMeasConfig;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-ue-phy.cc ns-3.42/src/lte/model/lte-ue-phy.cc
--- ns-3.41/src/lte/model/lte-ue-phy.cc	2024-02-09 14:44:08.325793000 -0800
+++ ns-3.42/src/lte/model/lte-ue-phy.cc	2024-05-29 15:29:47.120073600 -0700
@@ -1467,10 +1467,10 @@
         m_dlBandwidth = dlBandwidth;
 
         static const int Type0AllocationRbg[4] = {
-            10,  // RGB size 1
-            26,  // RGB size 2
-            63,  // RGB size 3
-            110, // RGB size 4
+            10,  // RBG size 1
+            26,  // RBG size 2
+            63,  // RBG size 3
+            110, // RBG size 4
         };       // see table 7.1.6.1-1 of 36.213
         for (int i = 0; i < 4; i++)
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-ue-rrc.cc ns-3.42/src/lte/model/lte-ue-rrc.cc
--- ns-3.41/src/lte/model/lte-ue-rrc.cc	2024-02-09 14:44:08.325793000 -0800
+++ ns-3.42/src/lte/model/lte-ue-rrc.cc	2024-05-29 15:29:47.120073600 -0700
@@ -43,6 +43,7 @@
 
 namespace ns3
 {
+const Time UE_MEASUREMENT_REPORT_DELAY = MicroSeconds(1);
 
 NS_LOG_COMPONENT_DEFINE("LteUeRrc");
 
@@ -900,7 +901,6 @@
 
     case IDLE_WAIT_MIB_SIB1:
         // MIB has not been received, so ignore this SIB1
-        break;
 
     default: // e.g. IDLE_START, IDLE_CELL_SEARCH, IDLE_WAIT_MIB, IDLE_WAIT_SIB2
         // do nothing
@@ -1061,7 +1061,7 @@
         {
             NS_LOG_INFO("haveMobilityControlInfo == true");
             SwitchToState(CONNECTED_HANDOVER);
-            if (m_radioLinkFailureDetected.IsRunning())
+            if (m_radioLinkFailureDetected.IsPending())
             {
                 ResetRlfParams();
             }
@@ -2814,7 +2814,7 @@
     NS_ASSERT(!measReportIt->second.cellsTriggeredList.empty());
 
     // #issue 224, schedule only when there is no periodic event scheduled already
-    if (!measReportIt->second.periodicReportTimer.IsRunning())
+    if (!measReportIt->second.periodicReportTimer.IsPending())
     {
         measReportIt->second.numberOfReportsSent = 0;
         measReportIt->second.periodicReportTimer =
@@ -3272,8 +3272,6 @@
     case CONNECTED_HANDOVER:
     case CONNECTED_PHY_PROBLEM:
     case CONNECTED_REESTABLISHING:
-        break;
-
     default:
         break;
     }
@@ -3314,7 +3312,7 @@
     {
         m_radioLinkFailureDetected =
             Simulator::Schedule(m_t310, &LteUeRrc::RadioLinkFailureDetected, this);
-        if (m_radioLinkFailureDetected.IsRunning())
+        if (m_radioLinkFailureDetected.IsPending())
         {
             NS_LOG_INFO("t310 started");
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/lte-ue-rrc.h ns-3.42/src/lte/model/lte-ue-rrc.h
--- ns-3.41/src/lte/model/lte-ue-rrc.h	2024-02-09 14:44:08.325793000 -0800
+++ ns-3.42/src/lte/model/lte-ue-rrc.h	2024-05-29 15:29:47.120073600 -0700
@@ -60,7 +60,7 @@
  *  - time-to-trigger check is always performed before the reporting, so there
  *    would still be chance for it to cancel the reporting if necessary.
  */
-static const Time UE_MEASUREMENT_REPORT_DELAY = MicroSeconds(1);
+extern const Time UE_MEASUREMENT_REPORT_DELAY;
 
 class LteRlc;
 class LteMacSapProvider;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/pf-ff-mac-scheduler.cc ns-3.42/src/lte/model/pf-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/pf-ff-mac-scheduler.cc	2024-02-09 14:44:08.325793000 -0800
+++ ns-3.42/src/lte/model/pf-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -38,10 +38,10 @@
 
 /// PF type 0 allocation RBG
 static const int PfType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(PfFfMacScheduler);
@@ -1054,7 +1054,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_a30CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1122,7 +1122,7 @@
         for (uint8_t j = 0; j < nLayer; j++)
         {
             newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
@@ -2120,7 +2120,7 @@
 PfFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/pss-ff-mac-scheduler.cc ns-3.42/src/lte/model/pss-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/pss-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/model/pss-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -41,10 +41,10 @@
 
 /// PSS type 0 allocation RBG
 static const int PssType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(PssFfMacScheduler);
@@ -1378,7 +1378,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_a30CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1446,7 +1446,7 @@
         for (uint8_t j = 0; j < nLayer; j++)
         {
             newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
@@ -2421,7 +2421,7 @@
 PssFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/rr-ff-mac-scheduler.cc ns-3.42/src/lte/model/rr-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/rr-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/model/rr-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -40,10 +40,10 @@
 
 /// Type 0 allocation RBG
 static const int Type0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(RrFfMacScheduler);
@@ -1092,7 +1092,7 @@
         if (rbgAllocatedNum == rbgNum)
         {
             m_nextRntiDl = newEl.m_rnti; // store last RNTI served
-            break;                       // no more RGB to be allocated
+            break;                       // no more RBG to be allocated
         }
     } while ((*it).m_rnti != m_nextRntiDl);
 
@@ -1834,7 +1834,7 @@
 RrFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/tdbet-ff-mac-scheduler.cc ns-3.42/src/lte/model/tdbet-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/tdbet-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/model/tdbet-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -39,10 +39,10 @@
 
 /// TDBET type 0 allocation RBG
 static const int TdBetType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(TdBetFfMacScheduler);
@@ -960,7 +960,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_p10CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -981,7 +981,7 @@
                 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi((*itCqi).second));
             }
 
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             bytesTxed += tbSize;
@@ -1943,7 +1943,7 @@
 TdBetFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/tdmt-ff-mac-scheduler.cc ns-3.42/src/lte/model/tdmt-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/tdmt-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/model/tdmt-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -39,10 +39,10 @@
 
 /// TDMT type 0 allocation RBG
 static const int TdMtType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(TdMtFfMacScheduler);
@@ -965,7 +965,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_p10CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -984,7 +984,7 @@
                 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi((*itCqi).second));
             }
 
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
         }
@@ -1894,7 +1894,7 @@
 TdMtFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/tdtbfq-ff-mac-scheduler.cc ns-3.42/src/lte/model/tdtbfq-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/tdtbfq-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/model/tdtbfq-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -40,10 +40,10 @@
 
 /// TDTBFQ type 0 allocation RBG
 static const int TdTbfqType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(TdTbfqFfMacScheduler);
@@ -1106,7 +1106,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_a30CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1164,7 +1164,7 @@
         for (uint8_t j = 0; j < nLayer; j++)
         {
             newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             bytesTxed += tbSize;
@@ -2124,7 +2124,7 @@
 TdTbfqFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/model/tta-ff-mac-scheduler.cc ns-3.42/src/lte/model/tta-ff-mac-scheduler.cc
--- ns-3.41/src/lte/model/tta-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/model/tta-ff-mac-scheduler.cc	2024-05-29 15:29:47.120073600 -0700
@@ -39,10 +39,10 @@
 
 /// TTA type 0 allocation RBG
 static const int TtaType0AllocationRbg[4] = {
-    10,  // RGB size 1
-    26,  // RGB size 2
-    63,  // RGB size 3
-    110, // RGB size 4
+    10,  // RBG size 1
+    26,  // RBG size 2
+    63,  // RBG size 3
+    110, // RBG size 4
 };       // see table 7.1.6.1-1 of 36.213
 
 NS_OBJECT_ENSURE_REGISTERED(TtaFfMacScheduler);
@@ -996,7 +996,7 @@
             // Set to max value, to avoid divide by 0 below
             lcActives = (uint16_t)65535; // UINT16_MAX;
         }
-        uint16_t RgbPerRnti = (*itMap).second.size();
+        uint16_t RbgPerRnti = (*itMap).second.size();
         auto itCqi = m_a30CqiRxed.find((*itMap).first);
         auto itTxMode = m_uesTxMode.find((*itMap).first);
         if (itTxMode == m_uesTxMode.end())
@@ -1063,7 +1063,7 @@
         for (uint8_t j = 0; j < nLayer; j++)
         {
             newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
-            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
+            int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
                           8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
             newDci.m_tbsSize.push_back(tbSize);
             NS_LOG_INFO(this << " Layer " << (uint16_t)j << " MCS selected"
@@ -1975,7 +1975,7 @@
 TtaFfMacScheduler::TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
 {
     NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
-    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
+    FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params{};
     params.m_rnti = rnti;
     params.m_transmissionMode = txMode;
     m_cschedSapUser->CschedUeConfigUpdateInd(params);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/epc-test-gtpu.cc ns-3.42/src/lte/test/epc-test-gtpu.cc
--- ns-3.41/src/lte/test/epc-test-gtpu.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/epc-test-gtpu.cc	2024-05-29 15:29:47.124073500 -0700
@@ -33,9 +33,9 @@
  */
 
 EpsGtpuTestSuite::EpsGtpuTestSuite()
-    : TestSuite("epc-gtpu", SYSTEM)
+    : TestSuite("epc-gtpu", Type::SYSTEM)
 {
-    AddTestCase(new EpsGtpuHeaderTestCase(), TestCase::QUICK);
+    AddTestCase(new EpsGtpuHeaderTestCase(), TestCase::Duration::QUICK);
 }
 
 static EpsGtpuTestSuite epsGtpuTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/epc-test-s1u-downlink.cc ns-3.42/src/lte/test/epc-test-s1u-downlink.cc
--- ns-3.41/src/lte/test/epc-test-s1u-downlink.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/epc-test-s1u-downlink.cc	2024-05-29 15:29:47.124073500 -0700
@@ -267,14 +267,14 @@
 } g_epcS1uDlTestSuiteInstance;
 
 EpcS1uDlTestSuite::EpcS1uDlTestSuite()
-    : TestSuite("epc-s1u-downlink", SYSTEM)
+    : TestSuite("epc-s1u-downlink", Type::SYSTEM)
 {
     std::vector<EnbDlTestData> v1;
     EnbDlTestData e1;
     UeDlTestData f1(1, 100);
     e1.ues.push_back(f1);
     v1.push_back(e1);
-    AddTestCase(new EpcS1uDlTestCase("1 eNB, 1UE", v1), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("1 eNB, 1UE", v1), TestCase::Duration::QUICK);
 
     std::vector<EnbDlTestData> v2;
     EnbDlTestData e2;
@@ -283,12 +283,12 @@
     UeDlTestData f2_2(2, 200);
     e2.ues.push_back(f2_2);
     v2.push_back(e2);
-    AddTestCase(new EpcS1uDlTestCase("1 eNB, 2UEs", v2), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("1 eNB, 2UEs", v2), TestCase::Duration::QUICK);
 
     std::vector<EnbDlTestData> v3;
     v3.push_back(e1);
     v3.push_back(e2);
-    AddTestCase(new EpcS1uDlTestCase("2 eNBs", v3), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("2 eNBs", v3), TestCase::Duration::QUICK);
 
     EnbDlTestData e3;
     UeDlTestData f3_1(3, 50);
@@ -301,33 +301,37 @@
     v4.push_back(e3);
     v4.push_back(e1);
     v4.push_back(e2);
-    AddTestCase(new EpcS1uDlTestCase("3 eNBs", v4), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("3 eNBs", v4), TestCase::Duration::QUICK);
 
     std::vector<EnbDlTestData> v5;
     EnbDlTestData e5;
     UeDlTestData f5(10, 3000);
     e5.ues.push_back(f5);
     v5.push_back(e5);
-    AddTestCase(new EpcS1uDlTestCase("1 eNB, 10 pkts 3000 bytes each", v5), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("1 eNB, 10 pkts 3000 bytes each", v5),
+                TestCase::Duration::QUICK);
 
     std::vector<EnbDlTestData> v6;
     EnbDlTestData e6;
     UeDlTestData f6(50, 3000);
     e6.ues.push_back(f6);
     v6.push_back(e6);
-    AddTestCase(new EpcS1uDlTestCase("1 eNB, 50 pkts 3000 bytes each", v6), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("1 eNB, 50 pkts 3000 bytes each", v6),
+                TestCase::Duration::QUICK);
 
     std::vector<EnbDlTestData> v7;
     EnbDlTestData e7;
     UeDlTestData f7(10, 15000);
     e7.ues.push_back(f7);
     v7.push_back(e7);
-    AddTestCase(new EpcS1uDlTestCase("1 eNB, 10 pkts 15000 bytes each", v7), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("1 eNB, 10 pkts 15000 bytes each", v7),
+                TestCase::Duration::QUICK);
 
     std::vector<EnbDlTestData> v8;
     EnbDlTestData e8;
     UeDlTestData f8(100, 15000);
     e8.ues.push_back(f8);
     v8.push_back(e8);
-    AddTestCase(new EpcS1uDlTestCase("1 eNB, 100 pkts 15000 bytes each", v8), TestCase::QUICK);
+    AddTestCase(new EpcS1uDlTestCase("1 eNB, 100 pkts 15000 bytes each", v8),
+                TestCase::Duration::QUICK);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/epc-test-s1u-uplink.cc ns-3.42/src/lte/test/epc-test-s1u-uplink.cc
--- ns-3.41/src/lte/test/epc-test-s1u-uplink.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/epc-test-s1u-uplink.cc	2024-05-29 15:29:47.124073500 -0700
@@ -508,14 +508,14 @@
 } g_epcS1uUlTestSuiteInstance;
 
 EpcS1uUlTestSuite::EpcS1uUlTestSuite()
-    : TestSuite("epc-s1u-uplink", SYSTEM)
+    : TestSuite("epc-s1u-uplink", Type::SYSTEM)
 {
     std::vector<EnbUlTestData> v1;
     EnbUlTestData e1;
     UeUlTestData f1(1, 100, 1, 1);
     e1.ues.push_back(f1);
     v1.push_back(e1);
-    AddTestCase(new EpcS1uUlTestCase("1 eNB, 1UE", v1), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("1 eNB, 1UE", v1), TestCase::Duration::QUICK);
 
     std::vector<EnbUlTestData> v2;
     EnbUlTestData e2;
@@ -524,12 +524,12 @@
     UeUlTestData f2_2(2, 200, 2, 1);
     e2.ues.push_back(f2_2);
     v2.push_back(e2);
-    AddTestCase(new EpcS1uUlTestCase("1 eNB, 2UEs", v2), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("1 eNB, 2UEs", v2), TestCase::Duration::QUICK);
 
     std::vector<EnbUlTestData> v3;
     v3.push_back(e1);
     v3.push_back(e2);
-    AddTestCase(new EpcS1uUlTestCase("2 eNBs", v3), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("2 eNBs", v3), TestCase::Duration::QUICK);
 
     EnbUlTestData e3;
     UeUlTestData f3_1(3, 50, 1, 1);
@@ -542,33 +542,37 @@
     v4.push_back(e3);
     v4.push_back(e1);
     v4.push_back(e2);
-    AddTestCase(new EpcS1uUlTestCase("3 eNBs", v4), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("3 eNBs", v4), TestCase::Duration::QUICK);
 
     std::vector<EnbUlTestData> v5;
     EnbUlTestData e5;
     UeUlTestData f5(10, 3000, 1, 1);
     e5.ues.push_back(f5);
     v5.push_back(e5);
-    AddTestCase(new EpcS1uUlTestCase("1 eNB, 10 pkts 3000 bytes each", v5), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("1 eNB, 10 pkts 3000 bytes each", v5),
+                TestCase::Duration::QUICK);
 
     std::vector<EnbUlTestData> v6;
     EnbUlTestData e6;
     UeUlTestData f6(50, 3000, 1, 1);
     e6.ues.push_back(f6);
     v6.push_back(e6);
-    AddTestCase(new EpcS1uUlTestCase("1 eNB, 50 pkts 3000 bytes each", v6), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("1 eNB, 50 pkts 3000 bytes each", v6),
+                TestCase::Duration::QUICK);
 
     std::vector<EnbUlTestData> v7;
     EnbUlTestData e7;
     UeUlTestData f7(10, 15000, 1, 1);
     e7.ues.push_back(f7);
     v7.push_back(e7);
-    AddTestCase(new EpcS1uUlTestCase("1 eNB, 10 pkts 15000 bytes each", v7), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("1 eNB, 10 pkts 15000 bytes each", v7),
+                TestCase::Duration::QUICK);
 
     std::vector<EnbUlTestData> v8;
     EnbUlTestData e8;
     UeUlTestData f8(100, 15000, 1, 1);
     e8.ues.push_back(f8);
     v8.push_back(e8);
-    AddTestCase(new EpcS1uUlTestCase("1 eNB, 100 pkts 15000 bytes each", v8), TestCase::QUICK);
+    AddTestCase(new EpcS1uUlTestCase("1 eNB, 100 pkts 15000 bytes each", v8),
+                TestCase::Duration::QUICK);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-aggregation-throughput-scale.cc ns-3.42/src/lte/test/lte-test-aggregation-throughput-scale.cc
--- ns-3.41/src/lte/test/lte-test-aggregation-throughput-scale.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/lte-test-aggregation-throughput-scale.cc	2024-05-29 15:29:47.124073500 -0700
@@ -48,10 +48,10 @@
 NS_LOG_COMPONENT_DEFINE("LteAggregationThroughputScaleTest");
 
 LteAggregationThroughputScaleTestSuite::LteAggregationThroughputScaleTestSuite()
-    : TestSuite("lte-aggregation-throughput-scale", SYSTEM)
+    : TestSuite("lte-aggregation-throughput-scale", Type::SYSTEM)
 {
     AddTestCase(new LteAggregationThroughputScaleTestCase("Carrier aggregation throughput scale"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-carrier-aggregation.cc ns-3.42/src/lte/test/lte-test-carrier-aggregation.cc
--- ns-3.41/src/lte/test/lte-test-carrier-aggregation.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/lte-test-carrier-aggregation.cc	2024-05-29 15:29:47.124073500 -0700
@@ -80,7 +80,7 @@
 }
 
 TestCarrierAggregationSuite::TestCarrierAggregationSuite()
-    : TestSuite("lte-carrier-aggregation", SYSTEM)
+    : TestSuite("lte-carrier-aggregation", Type::SYSTEM)
 {
     NS_LOG_INFO("creating CarrierAggregationTestCase");
 
@@ -116,142 +116,214 @@
             return;
         }
 
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 100, 100, 1), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 100, 100, 1), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 100, 100, 1), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 100, 100, 1), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 100, 100, 1), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 100, 100, 1), TestCase::QUICK);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 100, 100, 2), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 100, 100, 2), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 100, 100, 2), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 100, 100, 2), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 100, 100, 2), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 100, 100, 2), TestCase::QUICK);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 100, 100, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 100, 100, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 100, 100, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 100, 100, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 100, 100, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 100, 100, 3), TestCase::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 100, 100, 1), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 100, 100, 1), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 100, 100, 1), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 100, 100, 1), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 100, 100, 1), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 100, 100, 1), TestCase::Duration::QUICK);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 100, 100, 2), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 100, 100, 2), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 100, 100, 2), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 100, 100, 2), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 100, 100, 2), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 100, 100, 2), TestCase::Duration::QUICK);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 100, 100, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 100, 100, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 100, 100, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 100, 100, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 100, 100, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 100, 100, 3), TestCase::Duration::QUICK);
     }
     else
     {
         // bandwidth is 25 and there are 2 carriers
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 25, 25, 2), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 4800, 25, 25, 2), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(3, 4800, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 4800, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 4800, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 4800, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 4800, 25, 25, 2), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 6000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 6000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 6000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 6000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 6000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 6000, 25, 25, 2), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 20000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 20000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 20000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 20000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 20000, 25, 25, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 20000, 25, 25, 2), TestCase::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 25, 25, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 25, 25, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 25, 25, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 25, 25, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 4800, 25, 25, 2), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(3, 4800, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 4800, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 4800, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 4800, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 4800, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 6000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 6000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 6000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 6000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 6000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 6000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 20000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 20000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 20000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 20000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 20000, 25, 25, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 20000, 25, 25, 2),
+                    TestCase::Duration::QUICK);
 
         // bandwidth is 25 and there are 3 carriers
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 25, 25, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 25, 25, 3), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 4800, 25, 25, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(3, 4800, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 4800, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 4800, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 4800, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 4800, 25, 25, 3), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 6000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 6000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 6000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 6000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 6000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 6000, 25, 25, 3), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 20000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 20000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 20000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 20000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 20000, 25, 25, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 20000, 25, 25, 3), TestCase::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 25, 25, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 25, 25, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 25, 25, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 25, 25, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 4800, 25, 25, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(3, 4800, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 4800, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 4800, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 4800, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 4800, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 6000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 6000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 6000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 6000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 6000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 6000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 20000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 20000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 20000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 20000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 20000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 20000, 25, 25, 3),
+                    TestCase::Duration::EXTENSIVE);
 
         // bandwidth = 6 RB and there are 3 carriers
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 6, 6, 3), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 4800, 6, 6, 3), TestCase::QUICK);
-        AddTestCase(new CarrierAggregationTestCase(3, 4800, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 4800, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 4800, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 4800, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 4800, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(1, 6000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 6000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 6000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 6000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 6000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 6000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(1, 20000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 20000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 20000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 20000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 20000, 6, 6, 3), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 20000, 6, 6, 3), TestCase::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 6, 6, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 6, 6, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 6, 6, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 6, 6, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 6, 6, 3), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 6, 6, 3), TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 4800, 6, 6, 3), TestCase::Duration::QUICK);
+        AddTestCase(new CarrierAggregationTestCase(3, 4800, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 4800, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 4800, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 4800, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 4800, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(1, 6000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 6000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 6000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 6000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 6000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 6000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(1, 20000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 20000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 20000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 20000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 20000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 20000, 6, 6, 3),
+                    TestCase::Duration::EXTENSIVE);
 
         // bandwidth = 6 RB and there are 2 carriers
-        AddTestCase(new CarrierAggregationTestCase(1, 0, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 0, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 0, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 0, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 0, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 0, 6, 6, 2), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 4800, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 4800, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 4800, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 4800, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 4800, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 4800, 6, 6, 2), TestCase::EXTENSIVE);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 6000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 6000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 6000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 6000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 6000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 6000, 6, 6, 2), TestCase::QUICK);
-
-        AddTestCase(new CarrierAggregationTestCase(1, 20000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(3, 20000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(6, 20000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(9, 20000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(12, 20000, 6, 6, 2), TestCase::EXTENSIVE);
-        AddTestCase(new CarrierAggregationTestCase(15, 20000, 6, 6, 2), TestCase::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(1, 0, 6, 6, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 0, 6, 6, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 0, 6, 6, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 0, 6, 6, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 0, 6, 6, 2), TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 0, 6, 6, 2), TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 4800, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 4800, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 4800, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 4800, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 4800, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 4800, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 6000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 6000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 6000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 6000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 6000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 6000, 6, 6, 2), TestCase::Duration::QUICK);
+
+        AddTestCase(new CarrierAggregationTestCase(1, 20000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(3, 20000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(6, 20000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(9, 20000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(12, 20000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
+        AddTestCase(new CarrierAggregationTestCase(15, 20000, 6, 6, 2),
+                    TestCase::Duration::EXTENSIVE);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-carrier-aggregation-configuration.cc ns-3.42/src/lte/test/lte-test-carrier-aggregation-configuration.cc
--- ns-3.41/src/lte/test/lte-test-carrier-aggregation-configuration.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/lte-test-carrier-aggregation-configuration.cc	2024-05-29 15:29:47.124073500 -0700
@@ -397,7 +397,7 @@
 };
 
 CarrierAggregationConfigTestSuite::CarrierAggregationConfigTestSuite()
-    : TestSuite("lte-carrier-aggregation-configuration", SYSTEM)
+    : TestSuite("lte-carrier-aggregation-configuration", Type::SYSTEM)
 {
     std::vector<ConfigToCheck> configToCheck;
 
@@ -419,7 +419,7 @@
                                                      numberOfComponentCarriers,
                                                      configToCheck,
                                                      simulationDuration),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     //   configToCheck.erase(configToCheck.begin(), configToCheck.end());
     configToCheck.clear();
@@ -446,7 +446,7 @@
                                                      numberOfComponentCarriers,
                                                      configToCheck,
                                                      simulationDuration),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-carrier-aggregation.h ns-3.42/src/lte/test/lte-test-carrier-aggregation.h
--- ns-3.41/src/lte/test/lte-test-carrier-aggregation.h	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/lte-test-carrier-aggregation.h	2024-05-29 15:29:47.124073500 -0700
@@ -71,7 +71,7 @@
      */
     void DlScheduling(DlSchedulingCallbackInfo dlInfo);
     /**
-     * UL Scheduling function that is used in this test as callback function of UL sceduling trace
+     * UL Scheduling function that is used in this test as callback function of UL scheduling trace
      * \param frameNo the frame number
      * \param subframeNo the subframe number
      * \param rnti the RNTI
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-cell-selection.cc ns-3.42/src/lte/test/lte-test-cell-selection.cc
--- ns-3.41/src/lte/test/lte-test-cell-selection.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/lte-test-cell-selection.cc	2024-05-29 15:29:47.124073500 -0700
@@ -60,7 +60,7 @@
  */
 
 LteCellSelectionTestSuite::LteCellSelectionTestSuite()
-    : TestSuite("lte-cell-selection", SYSTEM)
+    : TestSuite("lte-cell-selection", Type::SYSTEM)
 {
     std::vector<LteCellSelectionTestCase::UeSetup_t> w;
 
@@ -77,7 +77,7 @@
     };
 
     AddTestCase(new LteCellSelectionTestCase("EPC, real RRC", true, false, 60.0 /* isd */, w),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // IDEAL RRC PROTOCOL
 
@@ -92,7 +92,7 @@
     };
 
     AddTestCase(new LteCellSelectionTestCase("EPC, ideal RRC", true, true, 60.0 /* isd */, w),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
 } // end of LteCellSelectionTestSuite::LteCellSelectionTestSuite ()
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc	2024-02-09 14:44:08.329793200 -0800
+++ ns-3.42/src/lte/test/lte-test-cqa-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -65,7 +65,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestCqaFfMacScheduler");
 
 LenaTestCqaFfMacSchedulerSuite::LenaTestCqaFfMacSchedulerSuite()
-    : TestSuite("lte-cqa-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-cqa-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestCqaFfMacSchedulerSuite");
 
@@ -95,11 +95,11 @@
     //  6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 > 232000 -> throughput = 232000 bytes/sec
     //  12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 < 232000 -> throughput = 185000 bytes/sec
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(1, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(3, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(6, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // AddTestCase (new LenaCqaFfMacSchedulerTestCase1 (12,0,183000,185000,200,1,errorModel));//
     // simulation time = 1.5, otherwise, ul test will fail
@@ -122,11 +122,11 @@
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 < 232000 -> throughput =
     // 62000  bytes/sec
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(1, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(3, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(6, 4800, 230500, 125000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaCqaFfMacSchedulerTestCase1 (12,4800,115250,62000,200,1,errorModel)); //
     // simulation time = 1.5, otherwise, ul test will fail
 
@@ -149,11 +149,11 @@
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 < 232000 -> throughput =
     // 48667 bytes/sec
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(1, 6000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(3, 6000, 232000, 201000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(6, 6000, 198500, 97000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaCqaFfMacSchedulerTestCase1 (12,6000,99250,48667,200,1, errorModel)); //
     // simulation time = 1.5, otherwise, ul test will fail
 
@@ -175,18 +175,18 @@
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 < 232000 -> throughput = 32667
     // bytes/sec
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(1, 10000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(3, 10000, 232000, 137000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(6, 10000, 129166, 67000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaCqaFfMacSchedulerTestCase1 (12,10000,64583,32667,200,1,errorModel));//
     // simulation time = 1.5, otherwise, ul test will fail
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     AddTestCase(new LenaCqaFfMacSchedulerTestCase1(1, 100000, 0, 0, 200, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Case 2: homogeneous flow test in CQA (different distance)
     // Traffic1 info
@@ -211,7 +211,7 @@
     estThrCqaDl1.push_back(132000); // User 2 estimated TTI throughput from CQA
     estThrCqaDl1.push_back(132000); // User 3 estimated TTI throughput from CQA
     AddTestCase(new LenaCqaFfMacSchedulerTestCase2(dist1, estThrCqaDl1, packetSize1, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Traffic2 info
     //   UDP traffic: payload size = 200 bytes, interval = 1 ms
@@ -236,7 +236,7 @@
     estThrCqaDl2.push_back(230000); // User 2 estimated TTI throughput from CQA
     estThrCqaDl2.push_back(230000); // User 3 estimated TTI throughput from CQA
     AddTestCase(new LenaCqaFfMacSchedulerTestCase2(dist2, estThrCqaDl2, packetSize2, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Case 3: heterogeneous flow test in CQA
     //   UDP traffic: payload size = [100,200,300] bytes, interval = 1 ms
@@ -258,7 +258,7 @@
     estThrCqaDl3.push_back(232000); // User 1 estimated TTI throughput from CQA
     estThrCqaDl3.push_back(332000); // User 2 estimated TTI throughput from CQA
     AddTestCase(new LenaCqaFfMacSchedulerTestCase2(dist3, estThrCqaDl3, packetSize3, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-cqi-generation.cc ns-3.42/src/lte/test/lte-test-cqi-generation.cc
--- ns-3.41/src/lte/test/lte-test-cqi-generation.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-cqi-generation.cc	2024-05-29 15:29:47.124073500 -0700
@@ -89,59 +89,59 @@
  */
 
 LteCqiGenerationTestSuite::LteCqiGenerationTestSuite()
-    : TestSuite("lte-cqi-generation", SYSTEM)
+    : TestSuite("lte-cqi-generation", Type::SYSTEM)
 {
     //  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_DEBUG);
     //  LogComponentEnable ("LteCqiGenerationTest", logLevel);
     NS_LOG_INFO("Creating LteCqiGenerationTestSuite");
 
     AddTestCase(new LteCqiGenerationTestCase("UsePdcchForCqiGeneration", false, 4, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationTestCase("UsePdschForCqiGeneration", true, 28, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB0,
                                                            LteRrcSap::PdschConfigDedicated::dB0,
                                                            4,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB0,
                                                            LteRrcSap::PdschConfigDedicated::dB_3,
                                                            8,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB0,
                                                            LteRrcSap::PdschConfigDedicated::dB_6,
                                                            10,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB1,
                                                            LteRrcSap::PdschConfigDedicated::dB_6,
                                                            12,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB2,
                                                            LteRrcSap::PdschConfigDedicated::dB_6,
                                                            14,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB3,
                                                            LteRrcSap::PdschConfigDedicated::dB_6,
                                                            14,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteCqiGenerationDlPowerControlTestCase("CqiGenerationWithDlPowerControl",
                                                            LteRrcSap::PdschConfigDedicated::dB3,
                                                            LteRrcSap::PdschConfigDedicated::dB0,
                                                            8,
                                                            2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-deactivate-bearer.cc ns-3.42/src/lte/test/lte-test-deactivate-bearer.cc
--- ns-3.41/src/lte/test/lte-test-deactivate-bearer.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-deactivate-bearer.cc	2024-05-29 15:29:47.124073500 -0700
@@ -62,7 +62,7 @@
 {
 
 LenaTestBearerDeactivateSuite::LenaTestBearerDeactivateSuite()
-    : TestSuite("lte-test-deactivate-bearer", SYSTEM)
+    : TestSuite("lte-test-deactivate-bearer", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestPssFfMacSchedulerSuite");
 
@@ -95,7 +95,7 @@
 
     AddTestCase(
         new LenaDeactivateBearerTestCase(dist_1, estThrPssDl_1, packetSize_1, 1, errorModel, true),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-downlink-power-control.cc ns-3.42/src/lte/test/lte-test-downlink-power-control.cc
--- ns-3.41/src/lte/test/lte-test-downlink-power-control.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-downlink-power-control.cc	2024-05-29 15:29:47.124073500 -0700
@@ -53,7 +53,7 @@
  */
 
 LteDownlinkPowerControlTestSuite::LteDownlinkPowerControlTestSuite()
-    : TestSuite("lte-downlink-power-control", SYSTEM)
+    : TestSuite("lte-downlink-power-control", Type::SYSTEM)
 {
     //  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_DEBUG);
     //  LogComponentEnable ("LteDownlinkPowerControlTest", logLevel);
@@ -103,7 +103,7 @@
                         powerTxMap,
                         activeRbs_txpowdB30nrb6run1earfcn500,
                         spectrumValue_txpowdB30nrb6run1earfcn500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
     {
         // if power for RB not present, but RB is active, use powerTx
@@ -146,7 +146,7 @@
                         powerTxMap,
                         activeRbs_txpowdB30nrb6run1earfcn500,
                         spectrumValue_txpowdB30nrb6run1earfcn500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
     {
         std::vector<int> activeRbs_txpowdB30nrb25run1earfcn500(15);
@@ -239,7 +239,7 @@
                         powerTxMap,
                         activeRbs_txpowdB30nrb25run1earfcn500,
                         spectrumValue_txpowdB30nrb25run1earfcn500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
     {
         // if power for RB not present, but RB is active, use powerTx
@@ -323,56 +323,56 @@
                         powerTxMap,
                         activeRbs_txpowdB30nrb25run1earfcn500,
                         spectrumValue_txpowdB30nrb25run1earfcn500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 
     // Downlink DATA and CONTROL channels power comparison
     AddTestCase(new LteDownlinkPowerControlTestCase(false,
                                                     LteRrcSap::PdschConfigDedicated::dB0,
                                                     "DataCtrlPowerDifference_noChange"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB_6,
                                                     "DataCtrlPowerDifference_dB_6"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB_4dot77,
                                                     "DataCtrlPowerDifference_dB_4dot77"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB_3,
                                                     "DataCtrlPowerDifference_dB_3"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB_1dot77,
                                                     "DataCtrlPowerDifference_dB_1dot77"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB0,
                                                     "DataCtrlPowerDifference_dB0"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB1,
                                                     "DataCtrlPowerDifference_dB1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB2,
                                                     "DataCtrlPowerDifference_dB2"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkPowerControlTestCase(true,
                                                     LteRrcSap::PdschConfigDedicated::dB3,
                                                     "DataCtrlPowerDifference_dB3"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // RrcConnectionReconfiguration test
     AddTestCase(
         new LteDownlinkPowerControlRrcConnectionReconfigurationTestCase(false,
                                                                         "RrcConnReconf-IdealRrc"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteDownlinkPowerControlRrcConnectionReconfigurationTestCase(true,
                                                                         "RrcConnReconf-RealRrc"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 double
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-downlink-sinr.cc ns-3.42/src/lte/test/lte-test-downlink-sinr.cc
--- ns-3.41/src/lte/test/lte-test-downlink-sinr.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-downlink-sinr.cc	2024-05-29 15:29:47.124073500 -0700
@@ -46,7 +46,7 @@
  */
 
 LteDownlinkSinrTestSuite::LteDownlinkSinrTestSuite()
-    : TestSuite("lte-downlink-sinr", SYSTEM)
+    : TestSuite("lte-downlink-sinr", Type::SYSTEM)
 {
     /**
      * Build Spectrum Model values for the TX signal
@@ -81,9 +81,9 @@
     (*theoreticalSinr1)[1] = 3.72255684126076;
 
     AddTestCase(new LteDownlinkDataSinrTestCase(rxPsd1, theoreticalSinr1, "sdBm = [-46 -48]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkCtrlSinrTestCase(rxPsd1, theoreticalSinr1, "sdBm = [-46 -48]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     /**
      * TX signal #2: Power Spectral Density (W/Hz) of the signal of interest = [-63 -61] dBm and BW
@@ -98,9 +98,9 @@
     (*theoreticalSinr2)[1] = 0.1865697965291756;
 
     AddTestCase(new LteDownlinkDataSinrTestCase(rxPsd2, theoreticalSinr2, "sdBm = [-63 -61]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDownlinkCtrlSinrTestCase(rxPsd2, theoreticalSinr2, "sdBm = [-63 -61]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
@@ -157,10 +157,10 @@
      */
 
     // Number of packet bursts (1 data + 4 interferences)
-    const int numOfPbs = 5;
+    constexpr int numOfPbs = 5;
 
     // Number of packets in the packet bursts
-    const int numOfPkts = 10;
+    constexpr int numOfPkts = 10;
 
     // Packet bursts
     Ptr<PacketBurst> packetBursts[numOfPbs];
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-earfcn.cc ns-3.42/src/lte/test/lte-test-earfcn.cc
--- ns-3.41/src/lte/test/lte-test-earfcn.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-earfcn.cc	2024-05-29 15:29:47.124073500 -0700
@@ -166,31 +166,35 @@
 static LteEarfcnTestSuite g_lteEarfcnTestSuite;
 
 LteEarfcnTestSuite::LteEarfcnTestSuite()
-    : TestSuite("lte-earfcn", UNIT)
+    : TestSuite("lte-earfcn", Type::UNIT)
 {
     NS_LOG_FUNCTION(this);
 
-    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=500", 500, 2160e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=1000", 1000, 1970e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=1301", 1301, 1815.1e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=7000", 7000, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=20000", 20000, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=50000", 50000, 0.0), TestCase::QUICK);
+    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=500", 500, 2160e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=1000", 1000, 1970e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=1301", 1301, 1815.1e6),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=7000", 7000, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=20000", 20000, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnDlTestCase("DL EARFCN=50000", 50000, 0.0), TestCase::Duration::QUICK);
 
-    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=18100", 18100, 1930e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=19000", 19000, 1890e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=19400", 19400, 1730e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=10", 10, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=1000", 1000, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=50000", 50000, 0.0), TestCase::QUICK);
+    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=18100", 18100, 1930e6),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=19000", 19000, 1890e6),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=19400", 19400, 1730e6),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=10", 10, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=1000", 1000, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnUlTestCase("UL EARFCN=50000", 50000, 0.0), TestCase::Duration::QUICK);
 
-    AddTestCase(new LteEarfcnTestCase("EARFCN=500", 500, 2160e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=1000", 1000, 1970e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=1301", 1301, 1815.1e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=8000", 8000, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=50000", 50000, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=18100", 18100, 1930e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=19000", 19000, 1890e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=19400", 19400, 1730e6), TestCase::QUICK);
-    AddTestCase(new LteEarfcnTestCase("EARFCN=50000", 50000, 0.0), TestCase::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=500", 500, 2160e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=1000", 1000, 1970e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=1301", 1301, 1815.1e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=8000", 8000, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=50000", 50000, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=18100", 18100, 1930e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=19000", 19000, 1890e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=19400", 19400, 1730e6), TestCase::Duration::QUICK);
+    AddTestCase(new LteEarfcnTestCase("EARFCN=50000", 50000, 0.0), TestCase::Duration::QUICK);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-fdbet-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -56,7 +56,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestFdBetFfMacScheduler");
 
 LenaTestFdBetFfMacSchedulerSuite::LenaTestFdBetFfMacSchedulerSuite()
-    : TestSuite("lte-fdbet-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-fdbet-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestFdBetFfMacSchedulerSuite");
 
@@ -78,13 +78,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670 bytes/sec
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(3, 0, 749000, 749000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(6, 0, 373000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(12, 0, 185000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec
@@ -98,13 +98,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 bytes/sec
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(3, 4800, 469000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(6, 4800, 233500, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(12, 4800, 113000, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 18 -> 1191 -> 1191000 byte/sec
@@ -117,13 +117,13 @@
     // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(3, 6000, 389000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(6, 6000, 193000, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(12, 6000, 97000, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 10000 -> MCS 14 -> Itbs 13 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 13 -> 775 -> 775000 byte/sec
@@ -137,13 +137,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 bytes/sec
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 10000, 775000, 421000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(3, 10000, 253000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(6, 10000, 125000, 67000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(12, 10000, 61000, 32667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec
@@ -157,17 +157,18 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 2 -> 18 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(3, 20000, 137000, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(6, 20000, 67000, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(12, 20000, 32000, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaFdBetFfMacSchedulerTestCase1(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 
     // Test Case 2: fairness check
 
@@ -191,7 +192,7 @@
     estThrFdBetUl.push_back(26000);  // User 4 estimated TTI throughput from FDBET
     AddTestCase(
         new LenaFdBetFfMacSchedulerTestCase2(dist, estAchievableRateDl, estThrFdBetUl, errorModel),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-fdmt-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-fdmt-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-fdmt-ff-mac-scheduler.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-fdmt-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -56,7 +56,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestFdMtFfMacScheduler");
 
 LenaTestFdMtFfMacSchedulerSuite::LenaTestFdMtFfMacSchedulerSuite()
-    : TestSuite("lte-fdmt-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-fdmt-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestFdMtFfMacSchedulerSuite");
 
@@ -77,13 +77,13 @@
     // min 3 PRBs per UE: 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670
     // bytes/sec
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(3, 0, 2196000, 749000, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(6, 0, 2196000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(12, 0, 2196000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 byte/secfor one UE; 0 bytes/sec for other UEs
@@ -97,13 +97,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 bytes/sec
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(3, 4800, 1383000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(6, 4800, 1383000, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(12, 4800, 1383000, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 18 -> 1191 -> 1191000 byte/sec for one UE; 0 bytes/sec for other UEs
@@ -117,13 +117,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(3, 6000, 1191000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(6, 6000, 1191000, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(12, 6000, 1191000, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 10000 -> MCS 14 -> Itbs 13 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 13 -> 775 -> 775000 byte/sec for one UE; 0 bytes/sec for other UEs
@@ -137,13 +137,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 bytes/sec
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 10000, 775000, 437000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(3, 10000, 775000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(6, 10000, 775000, 67000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(12, 10000, 775000, 32667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DONWLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec for one UE; 0 bytes/sec for other UEs
@@ -157,17 +157,18 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 2 -> 26 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(3, 20000, 421000, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(6, 20000, 421000, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdMtFfMacSchedulerTestCase(12, 20000, 421000, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaFdMtFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-fdtbfq-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -63,7 +63,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestFdTbfqFfMacScheduler");
 
 LenaTestFdTbfqFfMacSchedulerSuite::LenaTestFdTbfqFfMacSchedulerSuite()
-    : TestSuite("lte-fdtbfq-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-fdtbfq-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestFdTbfqFfMacSchedulerSuite");
 
@@ -93,11 +93,11 @@
     //  6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 > 232000 -> throughput = 232000 bytes/sec
     //  12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 < 232000 -> throughput = 185000 bytes/sec
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(1, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(3, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(6, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaFdTbfqFfMacSchedulerTestCase1 (12,0,183000,185000,200,1,errorModel));//
     // simulation time = 1.5, otherwise, ul test will fail
 
@@ -119,11 +119,11 @@
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 < 232000 -> throughput =
     // 62000  bytes/sec
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(1, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(3, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(6, 4800, 230500, 125000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaFdTbfqFfMacSchedulerTestCase1 (12,4800,75250,62000,200,1,errorModel));
     // // simulation time = 1.5, otherwise, ul test will fail
 
@@ -146,11 +146,11 @@
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 < 232000 -> throughput =
     // 48667 bytes/sec
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(1, 6000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(3, 6000, 232000, 201000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(6, 6000, 198500, 97000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaFdTbfqFfMacSchedulerTestCase1 (12,6000,99250,48667,200,1, errorModel));
     // // simulation time = 1.5, otherwise, ul test will fail
 
@@ -172,11 +172,11 @@
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 < 232000 -> throughput = 32667
     // bytes/sec
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(1, 10000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(3, 10000, 232000, 137000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(6, 10000, 129166, 67000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaFdTbfqFfMacSchedulerTestCase1
     // (12,10000,64583,32667,200,1,errorModel));// simulation time = 1.5, otherwise, ul test will
     // fail
@@ -184,7 +184,7 @@
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     AddTestCase(new LenaFdTbfqFfMacSchedulerTestCase1(1, 100000, 0, 0, 200, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Case 2: homogeneous flow test in FDTBFQ (different distance)
     // Traffic1 info
@@ -210,7 +210,7 @@
     estThrFdTbfqDl1.push_back(132000); // User 3 estimated TTI throughput from FDTBFQ
     AddTestCase(
         new LenaFdTbfqFfMacSchedulerTestCase2(dist1, estThrFdTbfqDl1, packetSize1, 1, errorModel),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // Traffic2 info
     //   UDP traffic: payload size = 300 bytes, interval = 1 ms
@@ -236,7 +236,7 @@
     estThrFdTbfqDl2.push_back(302266); // User 3 estimated TTI throughput from FDTBFQ
     AddTestCase(
         new LenaFdTbfqFfMacSchedulerTestCase2(dist2, estThrFdTbfqDl2, packetSize2, 1, errorModel),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // Test Case 3: heterogeneous flow test in FDTBFQ
     //   UDP traffic: payload size = [100,200,300] bytes, interval = 1 ms
@@ -259,7 +259,7 @@
     estThrFdTbfqDl3.push_back(332000); // User 2 estimated TTI throughput from FDTBFQ
     AddTestCase(
         new LenaFdTbfqFfMacSchedulerTestCase2(dist3, estThrFdTbfqDl3, packetSize3, 1, errorModel),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-frequency-reuse.cc ns-3.42/src/lte/test/lte-test-frequency-reuse.cc
--- ns-3.41/src/lte/test/lte-test-frequency-reuse.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-frequency-reuse.cc	2024-05-29 15:29:47.124073500 -0700
@@ -57,7 +57,7 @@
  */
 
 LteFrequencyReuseTestSuite::LteFrequencyReuseTestSuite()
-    : TestSuite("lte-frequency-reuse", SYSTEM)
+    : TestSuite("lte-frequency-reuse", Type::SYSTEM)
 {
     //  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_DEBUG);
     //  LogComponentEnable ("LteFrequencyReuseTest", logLevel);
@@ -86,7 +86,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrPf2",
                                       5,
                                       "ns3::PfFfMacScheduler",
@@ -98,7 +98,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrPss1",
                                       1,
                                       "ns3::PssFfMacScheduler",
@@ -110,7 +110,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrPss2",
                                       5,
                                       "ns3::PssFfMacScheduler",
@@ -122,7 +122,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrCqa1",
                                       1,
                                       "ns3::CqaFfMacScheduler",
@@ -134,7 +134,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrCqa2",
                                       5,
                                       "ns3::CqaFfMacScheduler",
@@ -146,7 +146,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrFdTbfq1",
                                       1,
                                       "ns3::FdTbfqFfMacScheduler",
@@ -158,7 +158,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrFdTbfq2",
                                       5,
                                       "ns3::FdTbfqFfMacScheduler",
@@ -170,7 +170,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrTdTbfq1",
                                       1,
                                       "ns3::TdTbfqFfMacScheduler",
@@ -182,7 +182,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHardFrTestCase("DownlinkHardFrTdTbfq2",
                                       5,
                                       "ns3::TdTbfqFfMacScheduler",
@@ -194,7 +194,7 @@
                                       12,
                                       availableDlRb,
                                       availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     availableDlRb.clear();
     availableUlRb.clear();
@@ -232,7 +232,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrPf2",
                                         5,
                                         "ns3::PfFfMacScheduler",
@@ -246,7 +246,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrPss1",
                                         1,
                                         "ns3::PssFfMacScheduler",
@@ -260,7 +260,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrPss2",
                                         5,
                                         "ns3::PssFfMacScheduler",
@@ -274,7 +274,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrCqa1",
                                         1,
                                         "ns3::CqaFfMacScheduler",
@@ -288,7 +288,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrCqa2",
                                         5,
                                         "ns3::CqaFfMacScheduler",
@@ -302,7 +302,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrCqaFdTbfq1",
                                         1,
                                         "ns3::FdTbfqFfMacScheduler",
@@ -316,7 +316,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrCqaFdTbfq2",
                                         5,
                                         "ns3::FdTbfqFfMacScheduler",
@@ -330,7 +330,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrCqaTdTbfq1",
                                         1,
                                         "ns3::TdTbfqFfMacScheduler",
@@ -344,7 +344,7 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteStrictFrTestCase("DownlinkStrictFrCqaTdTbfq2",
                                         5,
                                         "ns3::TdTbfqFfMacScheduler",
@@ -358,80 +358,80 @@
                                         6,
                                         availableDlRb,
                                         availableUlRb),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new LteStrictFrAreaTestCase("LteStrictFrAreaTestCasePf1", "ns3::PfFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new LteStrictFrAreaTestCase("LteStrictFrAreaTestCasePss1", "ns3::PssFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteStrictFrAreaTestCase("LteStrictFrAreaTestCaseCqa1", "ns3::CqaFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteStrictFrAreaTestCase("LteStrictFrAreaTestCaseFdTbfq1", "ns3::FdTbfqFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteStrictFrAreaTestCase("LteStrictFrAreaTestCaseTdTbfq1", "ns3::TdTbfqFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(new LteSoftFrAreaTestCase("LteSoftFrAreaTestCasePf1", "ns3::PfFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteSoftFrAreaTestCase("LteSoftFrAreaTestCasePss1", "ns3::PssFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteSoftFrAreaTestCase("LteSoftFrAreaTestCaseCqa1", "ns3::CqaFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new LteSoftFrAreaTestCase("LteSoftFrAreaTestCaseFdTbfq1", "ns3::FdTbfqFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteSoftFrAreaTestCase("LteSoftFrAreaTestCaseTdTbfq1", "ns3::TdTbfqFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(new LteSoftFfrAreaTestCase("LteSoftFfrAreaTestCasePf1", "ns3::PfFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteSoftFfrAreaTestCase("LteSoftFfrAreaTestCasePss1", "ns3::PssFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteSoftFfrAreaTestCase("LteSoftFfrAreaTestCaseCqa1", "ns3::CqaFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new LteSoftFfrAreaTestCase("LteSoftFfrAreaTestCaseFdTbfq1", "ns3::FdTbfqFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteSoftFfrAreaTestCase("LteSoftFfrAreaTestCaseTdTbfq1", "ns3::TdTbfqFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     AddTestCase(
         new LteEnhancedFfrAreaTestCase("LteEnhancedFfrAreaTestCasePf1", "ns3::PfFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteEnhancedFfrAreaTestCase("LteEnhancedFfrAreaTestCasePss1", "ns3::PssFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(
         new LteEnhancedFfrAreaTestCase("LteEnhancedFfrAreaTestCaseCqa1", "ns3::CqaFfMacScheduler"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new LteEnhancedFfrAreaTestCase("LteEnhancedFfrAreaTestCaseFdTbfq1",
                                                "ns3::FdTbfqFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteEnhancedFfrAreaTestCase("LteEnhancedFfrAreaTestCaseTdTbfq1",
                                                "ns3::TdTbfqFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new LteDistributedFfrAreaTestCase("LteDistributedFfrAreaTestCasePf1",
                                                   "ns3::PfFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDistributedFfrAreaTestCase("LteDistributedFfrAreaTestCasePss1",
                                                   "ns3::PssFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDistributedFfrAreaTestCase("LteDistributedFfrAreaTestCaseCqa1",
                                                   "ns3::CqaFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDistributedFfrAreaTestCase("LteDistributedFfrAreaTestCaseFdTbfq1",
                                                   "ns3::FdTbfqFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteDistributedFfrAreaTestCase("LteDistributedFfrAreaTestCaseTdTbfq1",
                                                   "ns3::TdTbfqFfMacScheduler"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-harq.cc ns-3.42/src/lte/test/lte-test-harq.cc
--- ns-3.41/src/lte/test/lte-test-harq.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-harq.cc	2024-05-29 15:29:47.124073500 -0700
@@ -56,7 +56,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestHarq");
 
 LenaTestHarqSuite::LenaTestHarqSuite()
-    : TestSuite("lte-harq", SYSTEM)
+    : TestSuite("lte-harq", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestHarqTestCase");
 
@@ -64,13 +64,13 @@
     // MCS 0 TB size of 66 bytes SINR -9.91 dB expected throughput 31822 bytes/s
     // TBLER 1st tx 1.0
     // TBLER 2nd tx 0.074
-    AddTestCase(new LenaHarqTestCase(2, 2400, 66, 0.12, 31822), TestCase::QUICK);
+    AddTestCase(new LenaHarqTestCase(2, 2400, 66, 0.12, 31822), TestCase::Duration::QUICK);
 
     // Tests on DL/UL Data channels (PDSCH, PUSCH)
     // MCS 10 TB size of 472 bytes SINR 0.3 dB expected throughput 209964 bytes/s
     // TBLER 1st tx 1.0
     // TBLER 2nd tx 0.248
-    AddTestCase(new LenaHarqTestCase(1, 770, 472, 0.06, 209964), TestCase::QUICK);
+    AddTestCase(new LenaHarqTestCase(1, 770, 472, 0.06, 209964), TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-interference.cc ns-3.42/src/lte/test/lte-test-interference.cc
--- ns-3.41/src/lte/test/lte-test-interference.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-interference.cc	2024-05-29 15:29:47.124073500 -0700
@@ -65,15 +65,15 @@
  */
 
 LteInterferenceTestSuite::LteInterferenceTestSuite()
-    : TestSuite("lte-interference", SYSTEM)
+    : TestSuite("lte-interference", Type::SYSTEM)
 {
     // these two first test cases have a spectral efficiency that corresponds to CQI=0 (out of
     // range)
     // TODO: update the test conditions to handle out-of-range correctly
     // AddTestCase (new LteInterferenceTestCase ("d1=50, d2=10",  50.000000, 10.000000,  0.040000,
-    // 0.040000,  0.010399, 0.010399, 0, 0), TestCase::QUICK); AddTestCase (new
+    // 0.040000,  0.010399, 0.010399, 0, 0), TestCase::Duration::QUICK); AddTestCase (new
     // LteInterferenceTestCase ("d1=50, d2=20",  50.000000, 20.000000,  0.160000, 0.159998,
-    // 0.041154, 0.041153, 0, 0), TestCase::QUICK);
+    // 0.041154, 0.041153, 0, 0), TestCase::Duration::QUICK);
 
     AddTestCase(new LteInterferenceTestCase("d1=3000, d2=6000",
                                             3000.000000,
@@ -84,7 +84,7 @@
                                             0.389662,
                                             6,
                                             4),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=50",
                                             50.000000,
                                             50.000000,
@@ -94,7 +94,7 @@
                                             0.239808,
                                             2,
                                             2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=100",
                                             50.000000,
                                             100.000000,
@@ -104,7 +104,7 @@
                                             0.785042,
                                             6,
                                             6),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=200",
                                             50.000000,
                                             200.000000,
@@ -114,7 +114,7 @@
                                             1.959533,
                                             14,
                                             14),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=500",
                                             50.000000,
                                             500.000000,
@@ -124,7 +124,7 @@
                                             4.241793,
                                             22,
                                             22),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=1000",
                                             50.000000,
                                             1000.000000,
@@ -134,7 +134,7 @@
                                             6.144825,
                                             28,
                                             28),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=10000",
                                             50.000000,
                                             10000.000000,
@@ -144,7 +144,7 @@
                                             10.588084,
                                             28,
                                             28),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=100000",
                                             50.000000,
                                             100000.000000,
@@ -154,7 +154,7 @@
                                             10.928917,
                                             28,
                                             28),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=50, d2=1000000",
                                             50.000000,
                                             1000000.000000,
@@ -164,7 +164,7 @@
                                             10.932767,
                                             28,
                                             28),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=4500, d2=12600",
                                             4500.000000,
                                             12600.000000,
@@ -174,7 +174,7 @@
                                             0.270399,
                                             8,
                                             2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceTestCase("d1=5400, d2=12600",
                                             5400.000000,
                                             12600.000000,
@@ -184,7 +184,7 @@
                                             0.193019,
                                             6,
                                             0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-interference-fr.cc ns-3.42/src/lte/test/lte-test-interference-fr.cc
--- ns-3.41/src/lte/test/lte-test-interference-fr.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-interference-fr.cc	2024-05-29 15:29:47.124073500 -0700
@@ -51,7 +51,7 @@
  */
 
 LteInterferenceFrTestSuite::LteInterferenceFrTestSuite()
-    : TestSuite("lte-interference-fr", SYSTEM)
+    : TestSuite("lte-interference-fr", Type::SYSTEM)
 {
     //  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_DEBUG);
     //  LogComponentEnable ("LteInterferenceFrTest", logLevel);
@@ -61,25 +61,25 @@
                                                   20.000000,
                                                   356449.932732,
                                                   10803.280215),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceHardFrTestCase("d1=50, d2=50",
                                                   50.000000,
                                                   50.000000,
                                                   356449.932732,
                                                   10803.280215),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceHardFrTestCase("d1=50, d2=200",
                                                   50.000000,
                                                   200.000000,
                                                   356449.932732,
                                                   10803.280215),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceHardFrTestCase("d1=50, d2=500",
                                                   50.000000,
                                                   500.000000,
                                                   356449.932732,
                                                   10803.280215),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new LteInterferenceStrictFrTestCase("d1=50, d2=20",
                                                     50.000000,
@@ -89,7 +89,7 @@
                                                     356449.932732,
                                                     10803.280215,
                                                     18),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceStrictFrTestCase("d1=50, d2=50",
                                                     50.000000,
                                                     50.000000,
@@ -98,7 +98,7 @@
                                                     356449.932732,
                                                     10803.280215,
                                                     28),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceStrictFrTestCase("d1=50, d2=200",
                                                     50.000000,
                                                     200.000000,
@@ -107,7 +107,7 @@
                                                     356449.932732,
                                                     10803.280215,
                                                     30),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteInterferenceStrictFrTestCase("d1=50, d2=500",
                                                     50.000000,
                                                     500.000000,
@@ -116,7 +116,7 @@
                                                     356449.932732,
                                                     10803.280215,
                                                     30),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-ipv6-routing.cc ns-3.42/src/lte/test/lte-test-ipv6-routing.cc
--- ns-3.41/src/lte/test/lte-test-ipv6-routing.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-ipv6-routing.cc	2024-05-29 15:29:47.124073500 -0700
@@ -387,9 +387,9 @@
 };
 
 LteIpv6RoutingTestSuite::LteIpv6RoutingTestSuite()
-    : TestSuite("lte-ipv6-routing-test", UNIT)
+    : TestSuite("lte-ipv6-routing-test", Type::UNIT)
 {
-    AddTestCase(new LteIpv6RoutingTestCase, TestCase::QUICK);
+    AddTestCase(new LteIpv6RoutingTestCase, TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-link-adaptation.cc ns-3.42/src/lte/test/lte-test-link-adaptation.cc
--- ns-3.41/src/lte/test/lte-test-link-adaptation.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-link-adaptation.cc	2024-05-29 15:29:47.124073500 -0700
@@ -52,7 +52,7 @@
  */
 
 LteLinkAdaptationTestSuite::LteLinkAdaptationTestSuite()
-    : TestSuite("lte-link-adaptation", SYSTEM)
+    : TestSuite("lte-link-adaptation", Type::SYSTEM)
 {
     NS_LOG_INFO("Creating LteLinkAdaptionTestSuite");
 
@@ -101,7 +101,7 @@
                                                   snrEfficiencyMcs[i].snrDb,
                                                   lossDb,
                                                   snrEfficiencyMcs[i].mcsIndex),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-mimo.cc ns-3.42/src/lte/test/lte-test-mimo.cc
--- ns-3.41/src/lte/test/lte-test-mimo.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-mimo.cc	2024-05-29 15:29:47.124073500 -0700
@@ -58,7 +58,7 @@
 NS_LOG_COMPONENT_DEFINE("LteTestMimo");
 
 LenaTestMimoSuite::LenaTestMimoSuite()
-    : TestSuite("lte-mimo", SYSTEM)
+    : TestSuite("lte-mimo", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaMimoTestCase");
 
@@ -72,13 +72,13 @@
     estThrDl.push_back(183600); // interval 2 : estimated throughput for TxMode 2
     estThrDl.push_back(193400); // interval 3 : estimated throughput for TxMode 3
     AddTestCase(new LenaMimoTestCase(300, estThrDl, "ns3::RrFfMacScheduler", true),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaMimoTestCase(300, estThrDl, "ns3::PfFfMacScheduler", true),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaMimoTestCase(300, estThrDl, "ns3::RrFfMacScheduler", false),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaMimoTestCase(300, estThrDl, "ns3::PfFfMacScheduler", false),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-pathloss-model.cc ns-3.42/src/lte/test/lte-test-pathloss-model.cc
--- ns-3.41/src/lte/test/lte-test-pathloss-model.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-pathloss-model.cc	2024-05-29 15:29:47.124073500 -0700
@@ -66,7 +66,7 @@
 }
 
 LtePathlossModelTestSuite::LtePathlossModelTestSuite()
-    : TestSuite("lte-pathloss-model", SYSTEM)
+    : TestSuite("lte-pathloss-model", Type::SYSTEM)
 {
     // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
     // LogComponentEnable ("LteHelper", logLevel);
@@ -137,7 +137,7 @@
         name << " snr= " << sinrDb << " dB, "
              << " mcs= " << snrEfficiencyMcs[i].mcsIndex;
         AddTestCase(new LtePathlossModelSystemTestCase(name.str(), sinrDb, dist[i], mcs),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-pf-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-pf-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -55,7 +55,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestPfFfMacScheduler");
 
 LenaTestPfFfMacSchedulerSuite::LenaTestPfFfMacSchedulerSuite()
-    : TestSuite("lte-pf-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-pf-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestPfFfMacSchedulerSuite");
 
@@ -77,15 +77,15 @@
     // 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670 bytes/sec
     // 15 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/15 UE/TTI -> 147730 bytes/sec
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(3, 0, 732000, 749000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(6, 0, 366000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(12, 0, 183000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(15, 0, 146400, 147730, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 15 -> 1383 -> 1383000 bytes/sec
@@ -101,15 +101,15 @@
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 bytes/sec
     // 15 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/15 UE/TTI  -> 49600 bytes/sec
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(3, 4800, 461000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(6, 4800, 230500, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(12, 4800, 115250, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(15, 4800, 92200, 49600, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 20 -> 1191 -> 1191000 bytes/sec
@@ -125,15 +125,15 @@
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     // 15 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/15 UE/TTI -> 38993 bytes/sec
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(3, 6000, 397000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(6, 6000, 198500, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(12, 6000, 99250, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(15, 6000, 79400, 38993, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 10000 -> MCS 14 -> Itbs 13 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 13 -> 871 -> 775000 bytes/sec
@@ -149,15 +149,15 @@
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 bytes/sec
     // 15 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/15 UE/TTI -> 26133 bytes/sec
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 10000, 775000, 437000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(3, 10000, 258333, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(6, 10000, 129167, 67000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(12, 10000, 64583, 32667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(15, 10000, 51667, 26133, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DONWLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec
@@ -173,19 +173,20 @@
     // 12 users -> 3 PRB at Itbs 2 -> 26 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     // 15 users -> 3 PRB at Itbs 2 -> 26 bytes * 8/15 UE/TTI -> 9600 bytes/sec
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(3, 20000, 140333, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(6, 20000, 70167, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(12, 20000, 35083, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPfFfMacSchedulerTestCase1(15, 20000, 28067, 9600, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaPfFfMacSchedulerTestCase1(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 
     // Test Case 2: fairness check
 
@@ -208,7 +209,7 @@
     estThrPfUl.push_back(85000);  // User 3 estimated TTI throughput from PF
     estThrPfUl.push_back(26000);  // User 4 estimated TTI throughput from PF
     AddTestCase(new LenaPfFfMacSchedulerTestCase2(dist, estThrPfDl, estThrPfUl, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-phy-error-model.cc ns-3.42/src/lte/test/lte-test-phy-error-model.cc
--- ns-3.41/src/lte/test/lte-test-phy-error-model.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-phy-error-model.cc	2024-05-29 15:29:47.124073500 -0700
@@ -57,7 +57,7 @@
 NS_LOG_COMPONENT_DEFINE("LteTestPhyErrorModel");
 
 LenaTestPhyErrorModelSuite::LenaTestPhyErrorModelSuite()
-    : TestSuite("lte-phy-error-model", SYSTEM)
+    : TestSuite("lte-phy-error-model", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestPhyErrorModelTestCase");
 
@@ -73,16 +73,19 @@
 
         // 1 interfering eNB SINR -2.0 BLER 0.007 TB size 217
         AddTestCase(new LenaDlCtrlPhyErrorModelTestCase(2, 1078, 0.007, 9, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::QUICK : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::QUICK : TestCase::Duration::TAKES_FOREVER);
         // 2 interfering eNBs SINR -4.0 BLER 0.037 TB size 217
         AddTestCase(new LenaDlCtrlPhyErrorModelTestCase(3, 1040, 0.045, 21, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
         // 3 interfering eNBs SINR -6.0 BLER 0.21 TB size 133
         AddTestCase(new LenaDlCtrlPhyErrorModelTestCase(4, 1250, 0.206, 40, Seconds(0.12), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
         // 4 interfering eNBs SINR -7.0 BLER 0.34 TB size 133
         AddTestCase(new LenaDlCtrlPhyErrorModelTestCase(5, 1260, 0.343, 47, Seconds(0.12), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
 
         // Tests on DL Data channels (PDSCH)
         // the tolerance is calculated with the following octave code:
@@ -94,23 +97,28 @@
 
         // MCS 2 TB size of 256 bits BLER 0.33 SINR -5.51
         AddTestCase(new LenaDataPhyErrorModelTestCase(4, 1800, 0.33, 39, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::QUICK : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::QUICK : TestCase::Duration::TAKES_FOREVER);
         // MCS 2 TB size of 528 bits BLER 0.11 SINR -5.51
         AddTestCase(new LenaDataPhyErrorModelTestCase(2, 1800, 0.11, 26, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
         // MCS 2 TB size of 1088 bits BLER 0.02 SINR -5.51
         AddTestCase(new LenaDataPhyErrorModelTestCase(1, 1800, 0.02, 33, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
         // MCS 12 TB size of 4800 bits  BLER 0.3  SINR 4.43
         AddTestCase(new LenaDataPhyErrorModelTestCase(1, 600, 0.3, 38, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
         // MCS 12 TB size of 1632 bits  BLER 0.55  SINR 4.43
         AddTestCase(new LenaDataPhyErrorModelTestCase(3, 600, 0.55, 40, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
         // MCS 16 TB size of 7272 bits (3648 x 3584) BLER 0.14 SINR 8.48
         // BLER 0.14 = 1 - ((1-0.075)*(1-0.075))
         AddTestCase(new LenaDataPhyErrorModelTestCase(1, 470, 0.14, 29, Seconds(0.04), rngRun),
-                    (rngRun == 1) ? TestCase::EXTENSIVE : TestCase::TAKES_FOREVER);
+                    (rngRun == 1) ? TestCase::Duration::EXTENSIVE
+                                  : TestCase::Duration::TAKES_FOREVER);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-primary-cell-change.cc ns-3.42/src/lte/test/lte-test-primary-cell-change.cc
--- ns-3.41/src/lte/test/lte-test-primary-cell-change.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-primary-cell-change.cc	2024-05-29 15:29:47.124073500 -0700
@@ -49,51 +49,51 @@
  */
 
 LtePrimaryCellChangeTestSuite::LtePrimaryCellChangeTestSuite()
-    : TestSuite("lte-primary-cell-change", SYSTEM)
+    : TestSuite("lte-primary-cell-change", Type::SYSTEM)
 {
     // Test that handover from eNB to eNB with one carrier works within this framework.
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 1, 0, 1),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 1, 0, 1),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test that handover between first carriers of eNBs works.
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 2, 0, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 2, 0, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test that handover from second carrier of first eNB to first carrier of second eNB works.
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 2, 1, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 2, 1, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test that handover from first carrier of first eNB to first carrier of second eNB works.
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 2, 0, 3),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 2, 0, 3),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test that handover from second carrier of first eNB to second carrier of second eNB works.
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 2, 1, 3),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 2, 1, 3),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test intra-eNB inter-frequency handover.
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 2, 0, 1),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 2, 0, 1),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 2, 1, 0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 2, 1, 0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("ideal RRC, RngRun=1", true, 1, 4, 3, 1),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LtePrimaryCellChangeTestCase("real RRC, RngRun=1", false, 1, 4, 3, 1),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 } // end of LtePrimaryCellChangeTestSuite::LtePrimaryCellChangeTestSuite ()
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-pss-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-pss-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-pss-ff-mac-scheduler.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-pss-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -63,7 +63,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestPssFfMacScheduler");
 
 LenaTestPssFfMacSchedulerSuite::LenaTestPssFfMacSchedulerSuite()
-    : TestSuite("lte-pss-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-pss-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestPssFfMacSchedulerSuite");
 
@@ -93,11 +93,11 @@
     //  6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 > 232000 -> throughput = 232000 bytes/sec
     //  12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 < 232000 -> throughput = 185000 bytes/sec
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(1, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(3, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(6, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // AddTestCase (new LenaPssFfMacSchedulerTestCase1 (12,0,183000,185000,200,1,errorModel));//
     // simulation time = 1.5, otherwise, ul test will fail
@@ -120,11 +120,11 @@
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 < 232000 -> throughput =
     // 62000  bytes/sec
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(1, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(3, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(6, 4800, 230500, 125000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaPssFfMacSchedulerTestCase1 (12,4800,115250,62000,200,1,errorModel)); //
     // simulation time = 1.5, otherwise, ul test will fail
 
@@ -147,11 +147,11 @@
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 < 232000 -> throughput =
     // 48667 bytes/sec
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(1, 6000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(3, 6000, 232000, 201000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(6, 6000, 198500, 97000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaPssFfMacSchedulerTestCase1 (12,6000,99250,48667,200,1, errorModel)); //
     // simulation time = 1.5, otherwise, ul test will fail
 
@@ -173,18 +173,18 @@
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 < 232000 -> throughput = 32667
     // bytes/sec
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(1, 10000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(3, 10000, 232000, 137000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(6, 10000, 129166, 67000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaPssFfMacSchedulerTestCase1 (12,10000,64583,32667,200,1,errorModel));//
     // simulation time = 1.5, otherwise, ul test will fail
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     AddTestCase(new LenaPssFfMacSchedulerTestCase1(1, 100000, 0, 0, 200, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Case 2: homogeneous flow test in PSS (different distance)
     // Traffic1 info
@@ -209,7 +209,7 @@
     estThrPssDl1.push_back(132000); // User 2 estimated TTI throughput from PSS
     estThrPssDl1.push_back(132000); // User 3 estimated TTI throughput from PSS
     AddTestCase(new LenaPssFfMacSchedulerTestCase2(dist1, estThrPssDl1, packetSize1, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Traffic2 info
     //   UDP traffic: payload size = 200 bytes, interval = 1 ms
@@ -234,7 +234,7 @@
     estThrPssDl2.push_back(230000); // User 2 estimated TTI throughput from PSS
     estThrPssDl2.push_back(230000); // User 3 estimated TTI throughput from PSS
     AddTestCase(new LenaPssFfMacSchedulerTestCase2(dist2, estThrPssDl2, packetSize2, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Case 3: heterogeneous flow test in PSS
     //   UDP traffic: payload size = [100,200,300] bytes, interval = 1 ms
@@ -256,7 +256,7 @@
     estThrPssDl3.push_back(232000); // User 1 estimated TTI throughput from PSS
     estThrPssDl3.push_back(332000); // User 2 estimated TTI throughput from PSS
     AddTestCase(new LenaPssFfMacSchedulerTestCase2(dist3, estThrPssDl3, packetSize3, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-radio-link-failure.cc ns-3.42/src/lte/test/lte-test-radio-link-failure.cc
--- ns-3.41/src/lte/test/lte-test-radio-link-failure.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-radio-link-failure.cc	2024-05-29 15:29:47.124073500 -0700
@@ -46,7 +46,7 @@
  * Test Suite
  */
 LteRadioLinkFailureTestSuite::LteRadioLinkFailureTestSuite()
-    : TestSuite("lte-radio-link-failure", SYSTEM)
+    : TestSuite("lte-radio-link-failure", Type::SYSTEM)
 {
     std::vector<Vector> uePositionList;
     std::vector<Vector> enbPositionList;
@@ -73,7 +73,7 @@
                                                 enbPositionList,
                                                 ueJumpAwayPosition,
                                                 checkConnectedList),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // One eNB: Real RRC PROTOCOL
     AddTestCase(new LteRadioLinkFailureTestCase(1,
@@ -84,7 +84,7 @@
                                                 enbPositionList,
                                                 ueJumpAwayPosition,
                                                 checkConnectedList),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Two eNBs: Ideal RRC PROTOCOL
 
@@ -99,7 +99,7 @@
                                                 enbPositionList,
                                                 ueJumpAwayPosition,
                                                 checkConnectedList),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Two eNBs: Ideal RRC PROTOCOL
     AddTestCase(new LteRadioLinkFailureTestCase(2,
@@ -110,7 +110,7 @@
                                                 enbPositionList,
                                                 ueJumpAwayPosition,
                                                 checkConnectedList),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
 } // end of LteRadioLinkFailureTestSuite::LteRadioLinkFailureTestSuite ()
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-rlc-am-e2e.cc ns-3.42/src/lte/test/lte-test-rlc-am-e2e.cc
--- ns-3.41/src/lte/test/lte-test-rlc-am-e2e.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-rlc-am-e2e.cc	2024-05-29 15:29:47.124073500 -0700
@@ -41,7 +41,7 @@
 NS_LOG_COMPONENT_DEFINE("LteRlcAmE2eTest");
 
 LteRlcAmE2eTestSuite::LteRlcAmE2eTestSuite()
-    : TestSuite("lte-rlc-am-e2e", SYSTEM)
+    : TestSuite("lte-rlc-am-e2e", Type::SYSTEM)
 {
     // NS_LOG_INFO ("Creating LteRlcAmE2eTestSuite");
 
@@ -77,18 +77,18 @@
                     break;
                 }
 
-                TestCase::TestDuration testDuration;
+                TestCase::Duration testDuration;
                 if (l == 1 && s == 0)
                 {
-                    testDuration = TestCase::QUICK;
+                    testDuration = TestCase::Duration::QUICK;
                 }
                 else if (s <= 4)
                 {
-                    testDuration = TestCase::EXTENSIVE;
+                    testDuration = TestCase::Duration::EXTENSIVE;
                 }
                 else
                 {
-                    testDuration = TestCase::TAKES_FOREVER;
+                    testDuration = TestCase::Duration::TAKES_FOREVER;
                 }
                 AddTestCase(new LteRlcAmE2eTestCase(name.str(), runs[s], losses[l], bulkSduArrival),
                             testDuration);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-rlc-am-transmitter.cc ns-3.42/src/lte/test/lte-test-rlc-am-transmitter.cc
--- ns-3.41/src/lte/test/lte-test-rlc-am-transmitter.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-rlc-am-transmitter.cc	2024-05-29 15:29:47.124073500 -0700
@@ -35,16 +35,19 @@
  */
 
 LteRlcAmTransmitterTestSuite::LteRlcAmTransmitterTestSuite()
-    : TestSuite("lte-rlc-am-transmitter", SYSTEM)
+    : TestSuite("lte-rlc-am-transmitter", Type::SYSTEM)
 {
     // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
     // LogComponentEnable ("LteRlcAmTransmitterTest", logLevel);
 
-    AddTestCase(new LteRlcAmTransmitterOneSduTestCase("One SDU, one PDU"), TestCase::QUICK);
-    AddTestCase(new LteRlcAmTransmitterSegmentationTestCase("Segmentation"), TestCase::QUICK);
-    AddTestCase(new LteRlcAmTransmitterConcatenationTestCase("Concatenation"), TestCase::QUICK);
+    AddTestCase(new LteRlcAmTransmitterOneSduTestCase("One SDU, one PDU"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteRlcAmTransmitterSegmentationTestCase("Segmentation"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteRlcAmTransmitterConcatenationTestCase("Concatenation"),
+                TestCase::Duration::QUICK);
     AddTestCase(new LteRlcAmTransmitterReportBufferStatusTestCase("ReportBufferStatus primitive"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-rlc-um-e2e.cc ns-3.42/src/lte/test/lte-test-rlc-um-e2e.cc
--- ns-3.41/src/lte/test/lte-test-rlc-um-e2e.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-rlc-um-e2e.cc	2024-05-29 15:29:47.124073500 -0700
@@ -48,7 +48,7 @@
  */
 
 LteRlcUmE2eTestSuite::LteRlcUmE2eTestSuite()
-    : TestSuite("lte-rlc-um-e2e", SYSTEM)
+    : TestSuite("lte-rlc-um-e2e", Type::SYSTEM)
 {
     // NS_LOG_INFO ("Creating LteRlcUmE2eTestSuite");
 
@@ -61,14 +61,14 @@
         {
             std::ostringstream name;
             name << " Losses = " << losses[l] << "%. Seed = " << seeds[s];
-            TestCase::TestDuration testDuration;
+            TestCase::Duration testDuration;
             if (l == 1 && s == 0)
             {
-                testDuration = TestCase::QUICK;
+                testDuration = TestCase::Duration::QUICK;
             }
             else
             {
-                testDuration = TestCase::EXTENSIVE;
+                testDuration = TestCase::Duration::EXTENSIVE;
             }
             AddTestCase(new LteRlcUmE2eTestCase(name.str(), seeds[s], losses[l]), testDuration);
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-rlc-um-transmitter.cc ns-3.42/src/lte/test/lte-test-rlc-um-transmitter.cc
--- ns-3.41/src/lte/test/lte-test-rlc-um-transmitter.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-rlc-um-transmitter.cc	2024-05-29 15:29:47.124073500 -0700
@@ -35,18 +35,21 @@
  */
 
 LteRlcUmTransmitterTestSuite::LteRlcUmTransmitterTestSuite()
-    : TestSuite("lte-rlc-um-transmitter", SYSTEM)
+    : TestSuite("lte-rlc-um-transmitter", Type::SYSTEM)
 {
     // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
     // LogComponentEnable ("LteRlcUmTransmitterTest", logLevel);
 
     // NS_LOG_INFO ("Creating LteRlcUmTransmitterTestSuite");
 
-    AddTestCase(new LteRlcUmTransmitterOneSduTestCase("One SDU, one PDU"), TestCase::QUICK);
-    AddTestCase(new LteRlcUmTransmitterSegmentationTestCase("Segmentation"), TestCase::QUICK);
-    AddTestCase(new LteRlcUmTransmitterConcatenationTestCase("Concatenation"), TestCase::QUICK);
+    AddTestCase(new LteRlcUmTransmitterOneSduTestCase("One SDU, one PDU"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteRlcUmTransmitterSegmentationTestCase("Segmentation"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteRlcUmTransmitterConcatenationTestCase("Concatenation"),
+                TestCase::Duration::QUICK);
     AddTestCase(new LteRlcUmTransmitterReportBufferStatusTestCase("ReportBufferStatus primitive"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-rr-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-rr-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-rr-ff-mac-scheduler.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-rr-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -53,7 +53,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestRrFfMacScheduler");
 
 LenaTestRrFfMacSchedulerSuite::LenaTestRrFfMacSchedulerSuite()
-    : TestSuite("lte-rr-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-rr-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaRrFfMacSchedulerTestCase");
 
@@ -75,17 +75,17 @@
     // 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670 bytes/sec
     // 15 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/15 UE/TTI -> 147730 bytes/sec
     AddTestCase(new LenaRrFfMacSchedulerTestCase(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(3, 0, 749000, 749000, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(6, 0, 373000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(9, 0, 185000, 246220, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(12, 0, 185000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(15, 0, 148000, 147730, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec
@@ -103,17 +103,17 @@
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 bytes/sec
     // 15 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/15 UE/TTI  -> 49600 bytes/sec
     AddTestCase(new LenaRrFfMacSchedulerTestCase(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(3, 4800, 469000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(6, 4800, 233000, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(9, 4800, 113000, 82667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(12, 4800, 113000, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(15, 4800, 90400, 49600, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 15 -> 1191 -> 1191000 bytes/sec
@@ -130,17 +130,17 @@
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     // 15 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/15 UE/TTI -> 38993 bytes/sec
     AddTestCase(new LenaRrFfMacSchedulerTestCase(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(3, 6000, 389000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(6, 6000, 193000, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(9, 6000, 97000, 64889, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(12, 6000, 97000, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(15, 6000, 77600, 38993, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec
@@ -158,21 +158,22 @@
     // 12 users -> 3 PRB at Itbs 2 -> 18 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     // 15 users -> 3 PRB at Itbs 2 -> 18 bytes * 8/15 UE/TTI -> 9600 bytes/sec
     AddTestCase(new LenaRrFfMacSchedulerTestCase(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(3, 20000, 137000, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(6, 20000, 67000, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(9, 20000, 32000, 16000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(12, 20000, 32000, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaRrFfMacSchedulerTestCase(15, 20000, 25600, 9600, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaRrFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaRrFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-secondary-cell-handover.cc ns-3.42/src/lte/test/lte-test-secondary-cell-handover.cc
--- ns-3.41/src/lte/test/lte-test-secondary-cell-handover.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-secondary-cell-handover.cc	2024-05-29 15:29:47.124073500 -0700
@@ -205,10 +205,10 @@
 };
 
 LteSecondaryCellHandoverTestSuite::LteSecondaryCellHandoverTestSuite()
-    : TestSuite{"lte-secondary-cell-handover", SYSTEM}
+    : TestSuite{"lte-secondary-cell-handover", Type::SYSTEM}
 {
-    AddTestCase(new LteSecondaryCellHandoverTestCase("Ideal RRC", true), TestCase::QUICK);
-    AddTestCase(new LteSecondaryCellHandoverTestCase("Real RRC", false), TestCase::QUICK);
+    AddTestCase(new LteSecondaryCellHandoverTestCase("Ideal RRC", true), TestCase::Duration::QUICK);
+    AddTestCase(new LteSecondaryCellHandoverTestCase("Real RRC", false), TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-secondary-cell-selection.cc ns-3.42/src/lte/test/lte-test-secondary-cell-selection.cc
--- ns-3.41/src/lte/test/lte-test-secondary-cell-selection.cc	2024-02-09 14:44:08.333793200 -0800
+++ ns-3.42/src/lte/test/lte-test-secondary-cell-selection.cc	2024-05-29 15:29:47.124073500 -0700
@@ -49,21 +49,21 @@
  */
 
 LteSecondaryCellSelectionTestSuite::LteSecondaryCellSelectionTestSuite()
-    : TestSuite("lte-secondary-cell-selection", SYSTEM)
+    : TestSuite("lte-secondary-cell-selection", Type::SYSTEM)
 {
     // REAL RRC PROTOCOL, either 2 or 4 UEs connecting to 2 or 4 component carriers
 
     AddTestCase(new LteSecondaryCellSelectionTestCase("EPC, real RRC, RngRun=1", false, 1U, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteSecondaryCellSelectionTestCase("EPC, real RRC, RngRun=1", false, 1U, 4),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // IDEAL RRC PROTOCOL, either 2 or 4 UEs connecting to 2 or 4 component carriers
 
     AddTestCase(new LteSecondaryCellSelectionTestCase("EPC, ideal RRC, RngRun=1", true, 1U, 2),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteSecondaryCellSelectionTestCase("EPC, ideal RRC, RngRun=1", true, 1U, 4),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
 } // end of LteSecondaryCellSelectionTestSuite::LteSecondaryCellSelectionTestSuite ()
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-spectrum-value-helper.cc ns-3.42/src/lte/test/lte-test-spectrum-value-helper.cc
--- ns-3.41/src/lte/test/lte-test-spectrum-value-helper.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-spectrum-value-helper.cc	2024-05-29 15:29:47.124073500 -0700
@@ -224,7 +224,7 @@
 static LteSpectrumValueHelperTestSuite g_lteSpectrumValueHelperTestSuite;
 
 LteSpectrumValueHelperTestSuite::LteSpectrumValueHelperTestSuite()
-    : TestSuite("lte-spectrum-value-helper", UNIT)
+    : TestSuite("lte-spectrum-value-helper", Type::UNIT)
 {
     //   LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
     //   LogComponentEnable ("LteSpectrumModelTestCase", logLevel);
@@ -240,7 +240,8 @@
     fc2160nrb6[3] = 2.160090000000e+09;
     fc2160nrb6[4] = 2.160270000000e+09;
     fc2160nrb6[5] = 2.160450000000e+09;
-    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb6", 500, 6, fc2160nrb6), TestCase::QUICK);
+    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb6", 500, 6, fc2160nrb6),
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc2160nrb15(15);
     fc2160nrb15[0] = 2.158740000000e+09;
@@ -258,7 +259,8 @@
     fc2160nrb15[12] = 2.160900000000e+09;
     fc2160nrb15[13] = 2.161080000000e+09;
     fc2160nrb15[14] = 2.161260000000e+09;
-    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb15", 500, 15, fc2160nrb15), TestCase::QUICK);
+    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb15", 500, 15, fc2160nrb15),
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc2160nrb25(25);
     fc2160nrb25[0] = 2.157840000000e+09;
@@ -286,7 +288,8 @@
     fc2160nrb25[22] = 2.161800000000e+09;
     fc2160nrb25[23] = 2.161980000000e+09;
     fc2160nrb25[24] = 2.162160000000e+09;
-    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb25", 500, 25, fc2160nrb25), TestCase::QUICK);
+    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb25", 500, 25, fc2160nrb25),
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc2160nrb50(50);
     fc2160nrb50[0] = 2.155590000000e+09;
@@ -339,7 +342,8 @@
     fc2160nrb50[47] = 2.164050000000e+09;
     fc2160nrb50[48] = 2.164230000000e+09;
     fc2160nrb50[49] = 2.164410000000e+09;
-    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb50", 500, 50, fc2160nrb50), TestCase::QUICK);
+    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb50", 500, 50, fc2160nrb50),
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc2160nrb75(75);
     fc2160nrb75[0] = 2.153340000000e+09;
@@ -417,7 +421,8 @@
     fc2160nrb75[72] = 2.166300000000e+09;
     fc2160nrb75[73] = 2.166480000000e+09;
     fc2160nrb75[74] = 2.166660000000e+09;
-    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb75", 500, 75, fc2160nrb75), TestCase::QUICK);
+    AddTestCase(new LteSpectrumModelTestCase("fc2160nrb75", 500, 75, fc2160nrb75),
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc2160nrb100(100);
     fc2160nrb100[0] = 2.151090000000e+09;
@@ -521,7 +526,7 @@
     fc2160nrb100[98] = 2.168730000000e+09;
     fc2160nrb100[99] = 2.168910000000e+09;
     AddTestCase(new LteSpectrumModelTestCase("fc2160nrb100", 500, 100, fc2160nrb100),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc1730nrb6(6);
     fc1730nrb6[0] = 1.729550000000e+09;
@@ -530,7 +535,8 @@
     fc1730nrb6[3] = 1.730090000000e+09;
     fc1730nrb6[4] = 1.730270000000e+09;
     fc1730nrb6[5] = 1.730450000000e+09;
-    AddTestCase(new LteSpectrumModelTestCase("fc1730nrb6", 19400, 6, fc1730nrb6), TestCase::QUICK);
+    AddTestCase(new LteSpectrumModelTestCase("fc1730nrb6", 19400, 6, fc1730nrb6),
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc1730nrb15(15);
     fc1730nrb15[0] = 1.728740000000e+09;
@@ -549,7 +555,7 @@
     fc1730nrb15[13] = 1.731080000000e+09;
     fc1730nrb15[14] = 1.731260000000e+09;
     AddTestCase(new LteSpectrumModelTestCase("fc1730nrb15", 19400, 15, fc1730nrb15),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc1730nrb25(25);
     fc1730nrb25[0] = 1.727840000000e+09;
@@ -578,7 +584,7 @@
     fc1730nrb25[23] = 1.731980000000e+09;
     fc1730nrb25[24] = 1.732160000000e+09;
     AddTestCase(new LteSpectrumModelTestCase("fc1730nrb25", 19400, 25, fc1730nrb25),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc1730nrb50(50);
     fc1730nrb50[0] = 1.725590000000e+09;
@@ -632,7 +638,7 @@
     fc1730nrb50[48] = 1.734230000000e+09;
     fc1730nrb50[49] = 1.734410000000e+09;
     AddTestCase(new LteSpectrumModelTestCase("fc1730nrb50", 19400, 50, fc1730nrb50),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc1730nrb75(75);
     fc1730nrb75[0] = 1.723340000000e+09;
@@ -711,7 +717,7 @@
     fc1730nrb75[73] = 1.736480000000e+09;
     fc1730nrb75[74] = 1.736660000000e+09;
     AddTestCase(new LteSpectrumModelTestCase("fc1730nrb75", 19400, 75, fc1730nrb75),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<double> fc1730nrb100(100);
     fc1730nrb100[0] = 1.721090000000e+09;
@@ -815,7 +821,7 @@
     fc1730nrb100[98] = 1.738730000000e+09;
     fc1730nrb100[99] = 1.738910000000e+09;
     AddTestCase(new LteSpectrumModelTestCase("fc1730nrb100", 19400, 100, fc1730nrb100),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     SpectrumValue nfdB0earfcn500nrb6(LteSpectrumValueHelper::GetSpectrumModel(500, 6));
     nfdB0earfcn500nrb6[0] = 4.002000000000e-21;
@@ -825,7 +831,7 @@
     nfdB0earfcn500nrb6[4] = 4.002000000000e-21;
     nfdB0earfcn500nrb6[5] = 4.002000000000e-21;
     AddTestCase(new LteNoisePsdTestCase("nfdB0earfcn500nrb6", 500, 6, 0.000000, nfdB0earfcn500nrb6),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     SpectrumValue nfdB5earfcn500nrb6(LteSpectrumValueHelper::GetSpectrumModel(500, 6));
     nfdB5earfcn500nrb6[0] = 1.265543519599e-20;
@@ -835,7 +841,7 @@
     nfdB5earfcn500nrb6[4] = 1.265543519599e-20;
     nfdB5earfcn500nrb6[5] = 1.265543519599e-20;
     AddTestCase(new LteNoisePsdTestCase("nfdB5earfcn500nrb6", 500, 6, 5.000000, nfdB5earfcn500nrb6),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     SpectrumValue nfdB10earfcn500nrb6(LteSpectrumValueHelper::GetSpectrumModel(500, 6));
     nfdB10earfcn500nrb6[0] = 4.002000000000e-20;
@@ -846,7 +852,7 @@
     nfdB10earfcn500nrb6[5] = 4.002000000000e-20;
     AddTestCase(
         new LteNoisePsdTestCase("nfdB10earfcn500nrb6", 500, 6, 10.000000, nfdB10earfcn500nrb6),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     SpectrumValue nfdB0earfcn500nrb15(LteSpectrumValueHelper::GetSpectrumModel(500, 15));
     nfdB0earfcn500nrb15[0] = 4.002000000000e-21;
@@ -866,7 +872,7 @@
     nfdB0earfcn500nrb15[14] = 4.002000000000e-21;
     AddTestCase(
         new LteNoisePsdTestCase("nfdB0earfcn500nrb15", 500, 15, 0.000000, nfdB0earfcn500nrb15),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     SpectrumValue nfdB5earfcn500nrb15(LteSpectrumValueHelper::GetSpectrumModel(500, 15));
     nfdB5earfcn500nrb15[0] = 1.265543519599e-20;
@@ -886,7 +892,7 @@
     nfdB5earfcn500nrb15[14] = 1.265543519599e-20;
     AddTestCase(
         new LteNoisePsdTestCase("nfdB5earfcn500nrb15", 500, 15, 5.000000, nfdB5earfcn500nrb15),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     SpectrumValue nfdB10earfcn500nrb15(LteSpectrumValueHelper::GetSpectrumModel(500, 15));
     nfdB10earfcn500nrb15[0] = 4.002000000000e-20;
@@ -922,7 +928,7 @@
                                      10.000000,
                                      activeRbs_txpowdB10nrb6run1earfcn500,
                                      spectrumValue_txpowdB10nrb6run1earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB30nrb6run1earfcn500(1);
     activeRbs_txpowdB30nrb6run1earfcn500[0] = 5.000000000000e+00;
@@ -940,7 +946,7 @@
                                      30.000000,
                                      activeRbs_txpowdB30nrb6run1earfcn500,
                                      spectrumValue_txpowdB30nrb6run1earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB10nrb25run1earfcn500(8);
     activeRbs_txpowdB10nrb25run1earfcn500[0] = 1.000000000000e+00;
@@ -984,7 +990,7 @@
                                      10.000000,
                                      activeRbs_txpowdB10nrb25run1earfcn500,
                                      spectrumValue_txpowdB10nrb25run1earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB30nrb25run1earfcn500(13);
     activeRbs_txpowdB30nrb25run1earfcn500[0] = 0.000000000000e+00;
@@ -1033,7 +1039,7 @@
                                      30.000000,
                                      activeRbs_txpowdB30nrb25run1earfcn500,
                                      spectrumValue_txpowdB30nrb25run1earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB10nrb100run1earfcn500(60);
     activeRbs_txpowdB10nrb100run1earfcn500[0] = 0.000000000000e+00;
@@ -1204,7 +1210,7 @@
                                      10.000000,
                                      activeRbs_txpowdB10nrb100run1earfcn500,
                                      spectrumValue_txpowdB10nrb100run1earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB30nrb100run1earfcn500(39);
     activeRbs_txpowdB30nrb100run1earfcn500[0] = 0.000000000000e+00;
@@ -1354,7 +1360,7 @@
                                      30.000000,
                                      activeRbs_txpowdB30nrb100run1earfcn500,
                                      spectrumValue_txpowdB30nrb100run1earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB10nrb6run2earfcn500(3);
     activeRbs_txpowdB10nrb6run2earfcn500[0] = 1.000000000000e+00;
@@ -1374,7 +1380,7 @@
                                      10.000000,
                                      activeRbs_txpowdB10nrb6run2earfcn500,
                                      spectrumValue_txpowdB10nrb6run2earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB30nrb6run2earfcn500(3);
     activeRbs_txpowdB30nrb6run2earfcn500[0] = 3.000000000000e+00;
@@ -1394,7 +1400,7 @@
                                      30.000000,
                                      activeRbs_txpowdB30nrb6run2earfcn500,
                                      spectrumValue_txpowdB30nrb6run2earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB10nrb25run2earfcn500(15);
     activeRbs_txpowdB10nrb25run2earfcn500[0] = 0.000000000000e+00;
@@ -1445,7 +1451,7 @@
                                      10.000000,
                                      activeRbs_txpowdB10nrb25run2earfcn500,
                                      spectrumValue_txpowdB10nrb25run2earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB30nrb25run2earfcn500(13);
     activeRbs_txpowdB30nrb25run2earfcn500[0] = 0.000000000000e+00;
@@ -1494,7 +1500,7 @@
                                      30.000000,
                                      activeRbs_txpowdB30nrb25run2earfcn500,
                                      spectrumValue_txpowdB30nrb25run2earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB10nrb100run2earfcn500(48);
     activeRbs_txpowdB10nrb100run2earfcn500[0] = 2.000000000000e+00;
@@ -1653,7 +1659,7 @@
                                      10.000000,
                                      activeRbs_txpowdB10nrb100run2earfcn500,
                                      spectrumValue_txpowdB10nrb100run2earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     std::vector<int> activeRbs_txpowdB30nrb100run2earfcn500(52);
     activeRbs_txpowdB30nrb100run2earfcn500[0] = 0.000000000000e+00;
@@ -1816,5 +1822,5 @@
                                      30.000000,
                                      activeRbs_txpowdB30nrb100run2earfcn500,
                                      spectrumValue_txpowdB30nrb100run2earfcn500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-tdbet-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -56,7 +56,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestTdBetFfMacScheduler");
 
 LenaTestTdBetFfMacSchedulerSuite::LenaTestTdBetFfMacSchedulerSuite()
-    : TestSuite("lte-tdbet-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-tdbet-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestTdBetFfMacSchedulerSuite");
 
@@ -78,13 +78,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670 bytes/sec
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(3, 0, 732000, 749000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(6, 0, 366000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(12, 0, 183000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec
@@ -98,13 +98,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 bytes/sec
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(3, 4800, 461000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(6, 4800, 230500, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(12, 4800, 115250, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 18 -> 1191 -> 1191000 byte/sec
@@ -117,13 +117,13 @@
     // 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(3, 6000, 397000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(6, 6000, 198500, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(12, 6000, 99250, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 10000 -> MCS 14 -> Itbs 13 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 13 -> 775 -> 775000 byte/sec
@@ -137,13 +137,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 bytes/sec
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 10000, 775000, 421000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(3, 10000, 258333, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(6, 10000, 129166, 67000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(12, 10000, 64583, 32667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec
@@ -157,17 +157,18 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 2 -> 18 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(3, 20000, 140333, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(6, 20000, 70166, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(12, 20000, 35083, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaTdBetFfMacSchedulerTestCase1(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 
     // Test Case 2: fairness check
 
@@ -191,7 +192,7 @@
     estThrTdBetUl.push_back(26000);  // User 4 estimated TTI throughput from TDBET
     AddTestCase(
         new LenaTdBetFfMacSchedulerTestCase2(dist, estAchievableRateDl, estThrTdBetUl, errorModel),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-tdmt-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-tdmt-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-tdmt-ff-mac-scheduler.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-tdmt-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -56,7 +56,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestTdMtFfMacScheduler");
 
 LenaTestTdMtFfMacSchedulerSuite::LenaTestTdMtFfMacSchedulerSuite()
-    : TestSuite("lte-tdmt-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-tdmt-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestTdMtFfMacSchedulerSuite");
 
@@ -77,13 +77,13 @@
     // min 3 PRBs per UE: 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670
     // bytes/sec
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(3, 0, 2196000, 749000, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(6, 0, 2196000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(12, 0, 2196000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 20 -> 1383 -> 1383000 bytes/sec for one UE; 0 bytes/sec for other
@@ -96,13 +96,13 @@
     // min 3 PRBs per UE: 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000
     // bytes/sec
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(3, 4800, 1383000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(6, 4800, 1383000, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(12, 4800, 1383000, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 18 -> 1191 -> 1191000 byte/sec for one UE; 0 bytes/sec for other UEs
@@ -116,13 +116,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(3, 6000, 1191000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(6, 6000, 1191000, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(12, 6000, 1191000, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 10000 -> MCS 14 -> Itbs 13 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 13 -> 775 -> 775000 byte/sec for one UE; 0 bytes/sec for other UEs
@@ -136,13 +136,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 bytes/sec
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 10000, 775000, 437000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(3, 10000, 775000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(6, 10000, 775000, 67000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(12, 10000, 775000, 32667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DONWLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec for one UE; 0 bytes/sec for other UEs
@@ -156,17 +156,18 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 2 -> 26 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(3, 20000, 421000, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(6, 20000, 421000, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdMtFfMacSchedulerTestCase(12, 20000, 421000, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaTdMtFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-tdtbfq-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -63,7 +63,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestTdTbfqFfMacScheduler");
 
 LenaTestTdTbfqFfMacSchedulerSuite::LenaTestTdTbfqFfMacSchedulerSuite()
-    : TestSuite("lte-tdtbfq-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-tdtbfq-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestTdTbfqFfMacSchedulerSuite");
 
@@ -93,11 +93,11 @@
     //  6 users -> 4 PRB at Itbs 26 -> 373 -> 373000 > 232000 -> throughput = 232000 bytes/sec
     //  12 users -> 2 PRB at Itbs 26 -> 185 -> 185000 < 232000 -> throughput = 185000 bytes/sec
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(1, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(3, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(6, 0, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaTdTbfqFfMacSchedulerTestCase1 (12,0,183000,185000,200,1,errorModel));//
     // simulation time = 1.5, otherwise, ul test will fail
 
@@ -119,11 +119,11 @@
     // 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000 < 232000 -> throughput =
     // 62000  bytes/sec
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(1, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(3, 4800, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(6, 4800, 230500, 125000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaTdTbfqFfMacSchedulerTestCase1 (12,4800,115250,62000,200,1,errorModel));
     // // simulation time = 1.5, otherwise, ul test will fail
 
@@ -146,11 +146,11 @@
     // 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 < 232000 -> throughput =
     // 48667 bytes/sec
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(1, 6000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(3, 6000, 232000, 201000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(6, 6000, 198500, 97000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaTdTbfqFfMacSchedulerTestCase1 (12,6000,99250,48667,200,1, errorModel));
     // // simulation time = 1.5, otherwise, ul test will fail
 
@@ -172,11 +172,11 @@
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 < 232000 -> throughput = 32667
     // bytes/sec
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(1, 10000, 232000, 232000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(3, 10000, 232000, 137000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(6, 10000, 129166, 67000, 200, 1, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     // AddTestCase (new LenaTdTbfqFfMacSchedulerTestCase1
     // (12,10000,64583,32667,200,1,errorModel));// simulation time = 1.5, otherwise, ul test will
     // fail
@@ -184,7 +184,7 @@
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     AddTestCase(new LenaTdTbfqFfMacSchedulerTestCase1(1, 100000, 0, 0, 200, 1, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Case 2: homogeneous flow test in TDTBFQ (different distance)
     // Traffic1 info
@@ -210,7 +210,7 @@
     estThrTdTbfqDl1.push_back(132000); // User 3 estimated TTI throughput from TDTBFQ
     AddTestCase(
         new LenaTdTbfqFfMacSchedulerTestCase2(dist1, estThrTdTbfqDl1, packetSize1, 1, errorModel),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // Traffic2 info
     //   UDP traffic: payload size = 300 bytes, interval = 1 ms
@@ -236,7 +236,7 @@
     estThrTdTbfqDl2.push_back(302500); // User 3 estimated TTI throughput from TDTBFQ
     AddTestCase(
         new LenaTdTbfqFfMacSchedulerTestCase2(dist2, estThrTdTbfqDl2, packetSize2, 1, errorModel),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // Test Case 3: heterogeneous flow test in TDTBFQ
     //   UDP traffic: payload size = [100,200,300] bytes, interval = 1 ms
@@ -259,7 +259,7 @@
     estThrTdTbfqDl3.push_back(332000); // User 2 estimated TTI throughput from TDTBFQ
     AddTestCase(
         new LenaTdTbfqFfMacSchedulerTestCase2(dist3, estThrTdTbfqDl3, packetSize3, 1, errorModel),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-tta-ff-mac-scheduler.cc ns-3.42/src/lte/test/lte-test-tta-ff-mac-scheduler.cc
--- ns-3.41/src/lte/test/lte-test-tta-ff-mac-scheduler.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-tta-ff-mac-scheduler.cc	2024-05-29 15:29:47.124073500 -0700
@@ -56,7 +56,7 @@
 NS_LOG_COMPONENT_DEFINE("LenaTestTtaFfMacScheduler");
 
 LenaTestTtaFfMacSchedulerSuite::LenaTestTtaFfMacSchedulerSuite()
-    : TestSuite("lte-tta-ff-mac-scheduler", SYSTEM)
+    : TestSuite("lte-tta-ff-mac-scheduler", Type::SYSTEM)
 {
     NS_LOG_INFO("creating LenaTestTtaFfMacSchedulerSuite");
 
@@ -77,15 +77,15 @@
     // min 3 PRBs per UE: 12 users -> 3 PRB at Itbs 26 -> 277 bytes * 8/12 UE/TTI -> 184670
     // bytes/sec
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 0, 2196000, 2292000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(3, 0, 2196000, 749000, errorModel),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(6, 0, 2196000, 373000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(12, 0, 2196000, 184670, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(15, 0, 2196000, 147730, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 4800 -> MCS 22 -> Itbs 20 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 15 -> 1383 -> 1383000 bytes/sec for one UE; 0 bytes/sec for other
@@ -98,13 +98,13 @@
     // min 3 PRBs per UE: 12 users -> 3 PRB at Itbs 13 -> 93  bytes * 8/12 UE/TTI  -> 62000
     // bytes/sec
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 4800, 1383000, 807000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(3, 4800, 1383000, 253000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(6, 4800, 1383000, 125000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(12, 4800, 1383000, 62000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 6000 -> MCS 20 -> Itbs 18 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 15 -> 1191 -> 1191000 bytes/sec for one UE; 0 bytes/sec for other
@@ -116,13 +116,13 @@
     // bytes/sec 6 users -> 4 PRB at Itbs 11 -> 97 -> 97000 bytes/sec after the patch enforcing min
     // 3 PRBs per UE: 12 users -> 3 PRB at Itbs 11 -> 73 bytes * 8/12 UE/TTI -> 48667 bytes/sec
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 6000, 1191000, 621000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(3, 6000, 1191000, 201000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(6, 6000, 1191000, 97000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(12, 6000, 1191000, 48667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 10000 -> MCS 14 -> Itbs 13 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 775 -> 775000 bytes/sec for one UE; 0 bytes/sec for other UEs
@@ -136,13 +136,13 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 8 -> 49 bytes * 8/12 UE/TTI -> 32667 bytes/sec
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 10000, 775000, 437000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(3, 10000, 775000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(6, 10000, 775000, 67000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(12, 10000, 775000, 32667, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DONWLINK - DISTANCE 20000 -> MCS 8 -> Itbs 8 (from table 7.1.7.2.1-1 of 36.213)
     // 1 user -> 24 PRB at Itbs 8 -> 421 -> 421000 bytes/sec for one UE; 0 bytes/sec for other UEs
@@ -156,17 +156,18 @@
     // after the patch enforcing min 3 PRBs per UE:
     // 12 users -> 3 PRB at Itbs 2 -> 26 bytes * 8/12 UE/TTI -> 12000 bytes/sec
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 20000, 421000, 137000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(3, 20000, 421000, 41000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(6, 20000, 421000, 22000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LenaTtaFfMacSchedulerTestCase(12, 20000, 421000, 12000, errorModel),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // DOWNLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
     // UPLINK - DISTANCE 100000 -> CQI == 0 -> out of range -> 0 bytes/sec
-    AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel), TestCase::QUICK);
+    AddTestCase(new LenaTtaFfMacSchedulerTestCase(1, 100000, 0, 0, errorModel),
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-ue-measurements.cc ns-3.42/src/lte/test/lte-test-ue-measurements.cc
--- ns-3.41/src/lte/test/lte-test-ue-measurements.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-ue-measurements.cc	2024-05-29 15:29:47.128073700 -0700
@@ -84,7 +84,7 @@
  */
 
 LteUeMeasurementsTestSuite::LteUeMeasurementsTestSuite()
-    : TestSuite("lte-ue-measurements", SYSTEM)
+    : TestSuite("lte-ue-measurements", Type::SYSTEM)
 {
     AddTestCase(new LteUeMeasurementsTestCase("d1=10, d2=10000",
                                               10.000000,
@@ -93,7 +93,7 @@
                                               -113.739702,
                                               -3.010305,
                                               -63.010305),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=20, d2=10000",
                                               20.000000,
                                               10000.000000,
@@ -101,7 +101,7 @@
                                               -113.739702,
                                               -3.010319,
                                               -56.989719),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=50, d2=10000",
                                               50.000000,
                                               10000.000000,
@@ -109,7 +109,7 @@
                                               -113.739702,
                                               -3.010421,
                                               -49.031021),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=100, d2=10000",
                                               100.000000,
                                               10000.000000,
@@ -117,7 +117,7 @@
                                               -113.739702,
                                               -3.010783,
                                               -43.010783),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=200, d2=10000",
                                               200.000000,
                                               10000.000000,
@@ -125,7 +125,7 @@
                                               -113.739702,
                                               -3.012232,
                                               -36.991632),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=100, d2=10000",
                                               100.000000,
                                               10000.000000,
@@ -133,7 +133,7 @@
                                               -113.739702,
                                               -3.010783,
                                               -43.010783),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=200, d2=10000",
                                               200.000000,
                                               10000.000000,
@@ -141,7 +141,7 @@
                                               -113.739702,
                                               -3.012232,
                                               -36.991632),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=500, d2=10000",
                                               500.000000,
                                               10000.000000,
@@ -149,7 +149,7 @@
                                               -113.739702,
                                               -3.022359,
                                               -29.042959),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=1000, d2=10000",
                                               1000.000000,
                                               10000.000000,
@@ -157,7 +157,7 @@
                                               -113.739702,
                                               -3.058336,
                                               -23.058336),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=2000, d2=10000",
                                               2000.000000,
                                               10000.000000,
@@ -165,7 +165,7 @@
                                               -113.739702,
                                               -3.199337,
                                               -17.178738),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=5000, d2=10000",
                                               5000.000000,
                                               10000.000000,
@@ -173,7 +173,7 @@
                                               -113.739702,
                                               -4.075793,
                                               -10.096393),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteUeMeasurementsTestCase("d1=10000, d2=10000",
                                               10000.000000,
                                               10000.000000,
@@ -181,7 +181,7 @@
                                               -113.739702,
                                               -6.257687,
                                               -6.257687),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=20000, d2=10000",
                                               20000.000000,
                                               10000.000000,
@@ -189,7 +189,7 @@
                                               -113.739702,
                                               -10.373365,
                                               -4.352765),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=50000, d2=10000",
                                               50000.000000,
                                               10000.000000,
@@ -197,7 +197,7 @@
                                               -113.739702,
                                               -17.605046,
                                               -3.625645),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=100000, d2=10000",
                                               100000.000000,
                                               10000.000000,
@@ -205,7 +205,7 @@
                                               -113.739702,
                                               -23.511071,
                                               -3.511071),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=200000, d2=10000",
                                               200000.000000,
                                               10000.000000,
@@ -213,7 +213,7 @@
                                               -113.739702,
                                               -29.502549,
                                               -3.481949),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=500000, d2=10000",
                                               500000.000000,
                                               10000.000000,
@@ -221,7 +221,7 @@
                                               -113.739702,
                                               -37.453160,
                                               -3.473760),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteUeMeasurementsTestCase("d1=1000000, d2=10000",
                                               1000000.000000,
                                               10000.000000,
@@ -229,7 +229,7 @@
                                               -113.739702,
                                               -43.472589,
                                               -3.472589),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 }
 
 /**
@@ -452,7 +452,7 @@
  */
 
 LteUeMeasurementsPiecewiseTestSuite1::LteUeMeasurementsPiecewiseTestSuite1()
-    : TestSuite("lte-ue-measurements-piecewise-1", SYSTEM)
+    : TestSuite("lte-ue-measurements-piecewise-1", Type::SYSTEM)
 {
     std::vector<Time> expectedTime;
     std::vector<uint8_t> expectedRsrp;
@@ -478,7 +478,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With normal threshold
     config.threshold1.range = 54;
@@ -491,7 +491,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With short time-to-trigger
     config.timeToTrigger = 64;
@@ -504,7 +504,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With long time-to-trigger
     config.timeToTrigger = 128;
@@ -517,7 +517,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With super time-to-trigger
     config.timeToTrigger = 256;
@@ -530,7 +530,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With hysteresis
     config.hysteresis = 8;
@@ -544,7 +544,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // With very high threshold
     config.threshold1.range = 97;
@@ -556,7 +556,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // === Event A2 (serving cell becomes worse than threshold) ===
 
@@ -570,7 +570,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With normal threshold
     config.threshold1.range = 54;
@@ -583,7 +583,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With short time-to-trigger
     config.timeToTrigger = 64;
@@ -596,7 +596,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With long time-to-trigger
     config.timeToTrigger = 128;
@@ -609,7 +609,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With super time-to-trigger
     config.timeToTrigger = 256;
@@ -622,7 +622,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With hysteresis
     config.hysteresis = 8;
@@ -636,7 +636,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // With very high threshold
     config.threshold1.range = 97;
@@ -652,7 +652,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     /*
      * Event A3, A4, and A5 are not tested intensively here because they depend on
@@ -672,7 +672,7 @@
                                                         config,
                                                         expectedTime,
                                                         expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // === Event A4 (neighbour becomes better than threshold) ===
 
@@ -682,7 +682,7 @@
                                                         config,
                                                         expectedTime,
                                                         expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // === Event A5 (PCell becomes worse than absolute threshold1 AND neighbour becomes better than
     // another absolute threshold2) ===
@@ -693,7 +693,7 @@
                                                         config,
                                                         expectedTime,
                                                         expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
 } // end of LteUeMeasurementsPiecewiseTestSuite1::LteUeMeasurementsPiecewiseTestSuite1
 
@@ -956,7 +956,7 @@
  */
 
 LteUeMeasurementsPiecewiseTestSuite2::LteUeMeasurementsPiecewiseTestSuite2()
-    : TestSuite("lte-ue-measurements-piecewise-2", SYSTEM)
+    : TestSuite("lte-ue-measurements-piecewise-2", Type::SYSTEM)
 {
     std::vector<Time> expectedTime;
     std::vector<uint8_t> expectedRsrp;
@@ -985,7 +985,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With normal threshold
     config.threshold1.range = 58;
@@ -998,7 +998,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With hysteresis
     config.hysteresis = 6;
@@ -1011,7 +1011,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // With very high threshold
     config.threshold1.range = 97;
@@ -1023,7 +1023,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // === Event A2 (serving cell becomes worse than threshold) ===
 
@@ -1037,7 +1037,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With normal threshold
     config.threshold1.range = 58;
@@ -1050,7 +1050,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With hysteresis
     config.hysteresis = 6;
@@ -1063,7 +1063,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // With very high threshold
     config.threshold1.range = 97;
@@ -1077,7 +1077,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // === Event A3 (neighbour becomes offset better than PCell) ===
 
@@ -1094,7 +1094,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With zero offset
     config.a3Offset = 0;
@@ -1107,7 +1107,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // With short time-to-trigger
     config.timeToTrigger = 160;
@@ -1120,7 +1120,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With super time-to-trigger
     config.timeToTrigger = 320;
@@ -1133,7 +1133,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With hysteresis and reportOnLeave
     config.hysteresis = 6;
@@ -1148,7 +1148,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // With negative offset
     config.a3Offset = -7;
@@ -1163,7 +1163,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // === Event A4 (neighbour becomes better than threshold) ===
 
@@ -1180,7 +1180,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With normal threshold
     config.threshold1.range = 58;
@@ -1193,7 +1193,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With short time-to-trigger
     config.timeToTrigger = 160;
@@ -1206,7 +1206,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With super time-to-trigger
     config.timeToTrigger = 320;
@@ -1219,7 +1219,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With hysteresis
     config.hysteresis = 6;
@@ -1233,7 +1233,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // With very high threshold
     config.threshold1.range = 97;
@@ -1245,7 +1245,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // === Event A5 (PCell becomes worse than absolute threshold1 AND neighbour becomes better than
     // another absolute threshold2) ===
@@ -1261,7 +1261,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With low-normal threshold
     config.threshold2.range = 58;
@@ -1270,7 +1270,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With low-high threshold
     config.threshold2.range = 97;
@@ -1279,7 +1279,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With normal-low threshold
     config.threshold1.range = 58;
@@ -1293,7 +1293,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With normal-normal threshold
     config.threshold2.range = 58;
@@ -1306,7 +1306,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With short time-to-trigger
     config.timeToTrigger = 160;
@@ -1319,7 +1319,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With super time-to-trigger
     config.timeToTrigger = 320;
@@ -1332,7 +1332,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // With hysteresis
     config.hysteresis = 6;
@@ -1346,7 +1346,7 @@
                                                 config,
                                                 expectedTime,
                                                 expectedRsrp),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // With normal-high threshold
     config.threshold2.range = 97;
@@ -1358,7 +1358,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With high-low threshold
     config.threshold1.range = 97;
@@ -1372,7 +1372,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // With high-normal threshold
     config.threshold2.range = 58;
@@ -1385,7 +1385,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // With high-high threshold
     config.threshold2.range = 97;
@@ -1396,7 +1396,7 @@
                     config,
                     expectedTime,
                     expectedRsrp),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
 } // end of LteUeMeasurementsPiecewiseTestSuite2::LteUeMeasurementsPiecewiseTestSuite2
 
@@ -1695,7 +1695,7 @@
  */
 
 LteUeMeasurementsPiecewiseTestSuite3::LteUeMeasurementsPiecewiseTestSuite3()
-    : TestSuite("lte-ue-measurements-piecewise-3", SYSTEM)
+    : TestSuite("lte-ue-measurements-piecewise-3", Type::SYSTEM)
 {
     std::vector<Time> expectedTime;
 
@@ -1724,7 +1724,7 @@
     AddTestCase(new LteUeMeasurementsPiecewiseTestCase3("Piecewise test case 3 - Event A4",
                                                         config,
                                                         expectedTime),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 } // end of LteUeMeasurementsPiecewiseTestSuite3::LteUeMeasurementsPiecewiseTestSuite3
 
 /**
@@ -1960,7 +1960,7 @@
  */
 
 LteUeMeasurementsHandoverTestSuite::LteUeMeasurementsHandoverTestSuite()
-    : TestSuite("lte-ue-measurements-handover", SYSTEM)
+    : TestSuite("lte-ue-measurements-handover", Type::SYSTEM)
 {
     std::list<LteRrcSap::ReportConfigEutra> sourceConfigList;
     std::list<LteRrcSap::ReportConfigEutra> targetConfigList;
@@ -2001,7 +2001,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::TAKES_FOREVER);
+        TestCase::Duration::TAKES_FOREVER);
 
     // increasing report interval
     sourceConfigList.front().reportInterval = LteRrcSap::ReportConfigEutra::MS120;
@@ -2017,7 +2017,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // === Event difference ===
 
@@ -2043,7 +2043,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // Event A2 to Event A1
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A2;
@@ -2056,7 +2056,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // Event A3 to Event A4
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A3;
@@ -2071,7 +2071,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // Event A4 to Event A3
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A4;
@@ -2086,7 +2086,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Event A2 to Event A3
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A2;
@@ -2101,7 +2101,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // Event A3 to Event A2
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A3;
@@ -2116,7 +2116,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // Event A4 to Event A5
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A4;
@@ -2131,7 +2131,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::TAKES_FOREVER);
+                TestCase::Duration::TAKES_FOREVER);
 
     // Event A5 to Event A4
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A5;
@@ -2146,7 +2146,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     // === Threshold/offset difference ===
 
@@ -2167,7 +2167,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // Event A2
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A2;
@@ -2183,7 +2183,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // Event A3
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A3;
@@ -2201,7 +2201,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // Event A4
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A4;
@@ -2217,7 +2217,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // Event A5
     sourceConfigList.front().eventId = LteRrcSap::ReportConfigEutra::EVENT_A5;
@@ -2233,7 +2233,7 @@
                                               expectedTime,
                                               expectedRsrp,
                                               Seconds(2)),
-        TestCase::EXTENSIVE);
+        TestCase::Duration::EXTENSIVE);
 
     // === Time-to-trigger (TTT) difference ===
 
@@ -2259,7 +2259,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(2)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // decreasing time-to-trigger (longer duration)
     sourceConfigList.front().timeToTrigger = 1024;
@@ -2274,7 +2274,7 @@
                                                       expectedTime,
                                                       expectedRsrp,
                                                       Seconds(4.2)),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
 } // end of LteUeMeasurementsHandoverTestSuite::LteUeMeasurementsHandoverTestSuite
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-uplink-power-control.cc ns-3.42/src/lte/test/lte-test-uplink-power-control.cc
--- ns-3.41/src/lte/test/lte-test-uplink-power-control.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-uplink-power-control.cc	2024-05-29 15:29:47.128073700 -0700
@@ -53,19 +53,20 @@
  */
 
 LteUplinkPowerControlTestSuite::LteUplinkPowerControlTestSuite()
-    : TestSuite("lte-uplink-power-control", SYSTEM)
+    : TestSuite("lte-uplink-power-control", Type::SYSTEM)
 {
     //  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_DEBUG);
     //  LogComponentEnable ("LteUplinkPowerControlTest", logLevel);
     NS_LOG_INFO("Creating LteUplinkPowerControlTestSuite");
 
-    AddTestCase(new LteUplinkOpenLoopPowerControlTestCase("OpenLoopTest1"), TestCase::QUICK);
+    AddTestCase(new LteUplinkOpenLoopPowerControlTestCase("OpenLoopTest1"),
+                TestCase::Duration::QUICK);
     AddTestCase(
         new LteUplinkClosedLoopPowerControlAbsoluteModeTestCase("ClosedLoopAbsoluteModeTest1"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new LteUplinkClosedLoopPowerControlAccumulatedModeTestCase(
                     "ClosedLoopAccumulatedModeTest1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/lte-test-uplink-sinr.cc ns-3.42/src/lte/test/lte-test-uplink-sinr.cc
--- ns-3.41/src/lte/test/lte-test-uplink-sinr.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/lte-test-uplink-sinr.cc	2024-05-29 15:29:47.128073700 -0700
@@ -43,7 +43,7 @@
  * TestSuite
  */
 LteUplinkSinrTestSuite::LteUplinkSinrTestSuite()
-    : TestSuite("lte-uplink-sinr", SYSTEM)
+    : TestSuite("lte-uplink-sinr", Type::SYSTEM)
 {
     /**
      * Build Spectrum Model values for the TX signal
@@ -85,13 +85,13 @@
                                               rxPsd2,
                                               theoreticalSinr1,
                                               "sdBm = [-46 -inf] and [-inf -48]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new LteUplinkSrsSinrTestCase(rxPsd1,
                                              rxPsd2,
                                              theoreticalSinr1,
                                              "sdBm = [-46 -inf] and [-inf -48]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     /**
      * TX signals #2: Power Spectral Density of the signals of interest = [-63 -inf] and [-inf -61]
@@ -113,13 +113,13 @@
                                               rxPsd4,
                                               theoreticalSinr2,
                                               "sdBm = [-63 -inf] and [-inf -61]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     AddTestCase(new LteUplinkSrsSinrTestCase(rxPsd3,
                                              rxPsd4,
                                              theoreticalSinr2,
                                              "sdBm = [-63 -inf] and [-inf -61]"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
@@ -177,12 +177,12 @@
      */
 
     // Number of packet bursts (2 data + 4 interferences)
-    const int numOfDataPbs = 2;
-    const int numOfIntfPbs = 4;
-    const int numOfPbs = numOfDataPbs + numOfIntfPbs;
+    constexpr int numOfDataPbs = 2;
+    constexpr int numOfIntfPbs = 4;
+    constexpr int numOfPbs = numOfDataPbs + numOfIntfPbs;
 
     // Number of packets in the packet bursts
-    const int numOfPkts = 10;
+    constexpr int numOfPkts = 10;
 
     // Packet bursts
     Ptr<PacketBurst> packetBursts[numOfPbs];
@@ -382,9 +382,9 @@
      */
 
     // Number of packet bursts (2 data + 4 interferences)
-    int numOfDataSignals = 2;
-    int numOfIntfSignals = 4;
-    int numOfSignals = numOfDataSignals + numOfIntfSignals;
+    constexpr int numOfDataSignals = 2;
+    constexpr int numOfIntfSignals = 4;
+    constexpr int numOfSignals = numOfDataSignals + numOfIntfSignals;
 
     uint16_t pbCellId[numOfSignals];
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/generate_test_data_lte_spectrum_value_noise.m ns-3.42/src/lte/test/reference/generate_test_data_lte_spectrum_value_noise.m
--- ns-3.41/src/lte/test/reference/generate_test_data_lte_spectrum_value_noise.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/generate_test_data_lte_spectrum_value_noise.m	2024-05-29 15:29:47.128073700 -0700
@@ -16,7 +16,7 @@
     npsdv = ones (1,nrbs) * (noise_psd * 10.^(noise_figure_dB/10));
 
     printf("SpectrumValue %s (LteSpectrumValueHelper::GetSpectrumModel (%d, %d));\n",
-	   name, earfcn, nrbs);
+           name, earfcn, nrbs);
 
     print_C_vector (npsdv, name);
     printf("AddTestCase (new LteNoisePsdTestCase (\"%s\", %d, %d, %f, %s));\n\n", name, earfcn, nrbs, noise_figure_dB, name);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/generate_test_data_lte_spectrum_value_txpsd.m ns-3.42/src/lte/test/reference/generate_test_data_lte_spectrum_value_txpsd.m
--- ns-3.41/src/lte/test/reference/generate_test_data_lte_spectrum_value_txpsd.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/generate_test_data_lte_spectrum_value_txpsd.m	2024-05-29 15:29:47.128073700 -0700
@@ -28,11 +28,11 @@
       print_C_vector (activeRbs, arname);
 
       printf("SpectrumValue %s (LteSpectrumValueHelper::GetSpectrumModel (%d, %d));\n",
-	     svname, earfcn, nrbs);
+             svname, earfcn, nrbs);
       print_C_vector (txpsd, svname);
 
       printf("AddTestCase (new LteTxPsdTestCase (\"%s\", %d, %d, %f, %s, %s));\n\n",
-	     basename, earfcn, nrbs, txpowdBm, arname, svname);
+             basename, earfcn, nrbs, txpowdBm, arname, svname);
 
     endfor
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/lte_cqi_generation.m ns-3.42/src/lte/test/reference/lte_cqi_generation.m
--- ns-3.41/src/lte/test/reference/lte_cqi_generation.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/lte_cqi_generation.m	2024-05-29 15:29:47.128073700 -0700
@@ -9,11 +9,11 @@
 
 nrbsControl = 25; % tx bandwidth configuration in number of RBs
 bwControl = nrbsControl * 180000; % bandwidth in Hz, note that this is smaller than
-		    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
+                                  % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
 
 nrbsData = 12; % tx bandwidth configuration in number of RBs
 bwData = nrbsData * 180000; % bandwidth in Hz, note that this is smaller than
-		    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
+                            % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
 
 kT = -174; % noise PSD in dBm / Hz
 ndBmData = kT + 10*log10(bwData);  % noise power dBm
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/lte_link_budget_interference_fr.m ns-3.42/src/lte/test/reference/lte_link_budget_interference_fr.m
--- ns-3.41/src/lte/test/reference/lte_link_budget_interference_fr.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/lte_link_budget_interference_fr.m	2024-05-29 15:29:47.128073700 -0700
@@ -8,7 +8,7 @@
 ful = 1930e6;  % UL carrier freq Hz, EARFCN = 18100
 nrbs = 25; % tx bandwidth configuration in number of RBs
 bw = nrbs * 180000; % bandwidth in Hz, note that this is smaller than
-		    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
+                    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
 kT = -174; % noise PSD in dBm / Hz
 ndBm = kT + 10*log10(bw);  % noise power dBm
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/lte_link_budget_interference.m ns-3.42/src/lte/test/reference/lte_link_budget_interference.m
--- ns-3.41/src/lte/test/reference/lte_link_budget_interference.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/lte_link_budget_interference.m	2024-05-29 15:29:47.128073700 -0700
@@ -8,7 +8,7 @@
 ful = 1930e6;  % UL carrier freq Hz, EARFCN = 18100
 nrbs = 25; % tx bandwidth configuration in number of RBs
 bw = nrbs * 180000; % bandwidth in Hz, note that this is smaller than
-		    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
+                    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
 kT = -174; % noise PSD in dBm / Hz
 ndBm = kT + 10*log10(bw);  % noise power dBm
 
@@ -73,7 +73,7 @@
 
 
   printf("AddTestCase (new LteInterferenceTestCase (\"d1=%d, d2=%d\", % f, %f, % f, %f, % f, %f, , ));\n", \
-	 d1, d2, d1, d2, dlsinr, ulsinr, dlse, ulse)
+         d1, d2, d1, d2, dlsinr, ulsinr, dlse, ulse)
 
 
 endfor
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/lte_link_budget.m ns-3.42/src/lte/test/reference/lte_link_budget.m
--- ns-3.41/src/lte/test/reference/lte_link_budget.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/lte_link_budget.m	2024-05-29 15:29:47.128073700 -0700
@@ -7,7 +7,7 @@
 f = 2160e6;  % carrier freq Hz, EARFCN = 500 (downlink)
 nrbs = 25; % tx bandwidth configuration in number of RBs
 bw = nrbs * 180000; % bandwidth in Hz, note that this is smaller than
-		    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
+                    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
 kT = -174; % noise PSD in dBm / Hz
 n = kT + 10*log10(bw);  % noise power dBm
 p = 30;  % tx power dBm
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/lte_link_budget_x2_handover_measures.m ns-3.42/src/lte/test/reference/lte_link_budget_x2_handover_measures.m
--- ns-3.41/src/lte/test/reference/lte_link_budget_x2_handover_measures.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/lte_link_budget_x2_handover_measures.m	2024-05-29 15:29:47.128073700 -0700
@@ -7,7 +7,7 @@
 f = 2160e6;  % carrier freq Hz, EARFCN = 500 (downlink)
 nrbs = 25; % tx bandwidth configuration in number of RBs
 bw = nrbs * 180000; % bandwidth in Hz, note that this is smaller than
-		    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
+                    % the nominal Channel Bandwidth, see TS 36.101 fig 5.6-1
 kT = -174; % noise PSD in dBm / Hz
 n = kT + 10*log10(bw);  % noise power dBm
 p = 20;  % tx power dBm
@@ -20,9 +20,9 @@
 %%d = logspace (0,5,100);
 x = linspace (0,4000,100);
 g1 = gain_freespace(abs (x-1000),f); % propagation gain from
-				% eNB 1
+                                     % eNB 1
 g2 = gain_freespace(abs (x-2000),f); % propagation gain from
-				% eNB 2
+                                     % eNB 2
 
 sinr1 = 10.*log10 (pW .* g1 ./ (nW + pW .* g2)); %dB
 sinr2 = 10.*log10 (pW .* g2 ./ (nW + pW .* g1)); %dB
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/reference/lte_uplink_power_control.m ns-3.42/src/lte/test/reference/lte_uplink_power_control.m
--- ns-3.41/src/lte/test/reference/lte_uplink_power_control.m	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/reference/lte_uplink_power_control.m	2024-05-29 15:29:47.128073700 -0700
@@ -46,19 +46,19 @@
 
 stepNumToExecute = 12;
 fcValueSequence = [
-		[0, 0];
-		[-1, 20];
-		[-1, 20];
-		[1, 1];
-		[3, 10];
-		[1, 15];
-		[3, 1];
-		[1, 10];
-		[1, 10];
-		[-1, 1];
-		[-1, 20];
-		[1, 5]
-                ];
+  [0, 0];
+  [-1, 20];
+  [-1, 20];
+  [1, 1];
+  [3, 10];
+  [1, 15];
+  [3, 1];
+  [1, 10];
+  [1, 10];
+  [-1, 1];
+  [-1, 20];
+  [1, 5]
+];
 
 %% distances
 %%                d1
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-asn1-encoding.cc ns-3.42/src/lte/test/test-asn1-encoding.cc
--- ns-3.41/src/lte/test/test-asn1-encoding.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-asn1-encoding.cc	2024-05-29 15:29:47.128073700 -0700
@@ -29,6 +29,7 @@
 #include "ns3/test.h"
 
 #include <iomanip>
+#include <vector>
 
 using namespace ns3;
 
@@ -49,13 +50,12 @@
      */
     static std::string sprintPacketContentsHex(Ptr<Packet> pkt)
     {
-        uint32_t psize = pkt->GetSize();
-        uint8_t buffer[psize];
+        std::vector<uint8_t> buffer(pkt->GetSize());
         std::ostringstream oss(std::ostringstream::out);
-        pkt->CopyData(buffer, psize);
-        for (uint32_t i = 0; i < psize; i++)
+        pkt->CopyData(buffer.data(), buffer.size());
+        for (auto b : buffer)
         {
-            oss << std::setfill('0') << std::setw(2) << std::hex << +(buffer[i]) << " ";
+            oss << std::setfill('0') << std::setw(2) << std::hex << +b << " ";
         }
         return std::string(oss.str() + "\n");
     }
@@ -67,13 +67,12 @@
      */
     static std::string sprintPacketContentsBin(Ptr<Packet> pkt)
     {
-        uint32_t psize = pkt->GetSize();
-        uint8_t buffer[psize];
+        std::vector<uint8_t> buffer(pkt->GetSize());
         std::ostringstream oss(std::ostringstream::out);
-        pkt->CopyData(buffer, psize);
-        for (uint32_t i = 0; i < psize; i++)
+        pkt->CopyData(buffer.data(), buffer.size());
+        for (auto b : buffer)
         {
-            oss << (std::bitset<8>(buffer[i]));
+            oss << (std::bitset<8>(b));
         }
         return std::string(oss.str() + "\n");
     }
@@ -561,7 +560,7 @@
     packet = Create<Packet>();
     NS_LOG_DEBUG("============= RrcConnectionReconfigurationTestCase ===========");
 
-    LteRrcSap::RrcConnectionReconfiguration msg;
+    LteRrcSap::RrcConnectionReconfiguration msg{};
     msg.rrcTransactionIdentifier = 2;
 
     msg.haveMeasConfig = true;
@@ -1256,20 +1255,20 @@
 };
 
 Asn1EncodingSuite::Asn1EncodingSuite()
-    : TestSuite("test-asn1-encoding", UNIT)
+    : TestSuite("test-asn1-encoding", Type::UNIT)
 {
     NS_LOG_FUNCTION(this);
-    AddTestCase(new RrcConnectionRequestTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionSetupTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionSetupCompleteTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionReconfigurationCompleteTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionReconfigurationTestCase(), TestCase::QUICK);
-    AddTestCase(new HandoverPreparationInfoTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionReestablishmentRequestTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionReestablishmentTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionReestablishmentCompleteTestCase(), TestCase::QUICK);
-    AddTestCase(new RrcConnectionRejectTestCase(), TestCase::QUICK);
-    AddTestCase(new MeasurementReportTestCase(), TestCase::QUICK);
+    AddTestCase(new RrcConnectionRequestTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionSetupTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionSetupCompleteTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionReconfigurationCompleteTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionReconfigurationTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new HandoverPreparationInfoTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionReestablishmentRequestTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionReestablishmentTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionReestablishmentCompleteTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new RrcConnectionRejectTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new MeasurementReportTestCase(), TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-epc-tft-classifier.cc ns-3.42/src/lte/test/test-epc-tft-classifier.cc
--- ns-3.41/src/lte/test/test-epc-tft-classifier.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-epc-tft-classifier.cc	2024-05-29 15:29:47.128073700 -0700
@@ -222,7 +222,7 @@
 static EpcTftClassifierTestSuite g_lteTftClassifierTestSuite;
 
 EpcTftClassifierTestSuite::EpcTftClassifierTestSuite()
-    : TestSuite("eps-tft-classifier", UNIT)
+    : TestSuite("eps-tft-classifier", Type::UNIT)
 {
     NS_LOG_FUNCTION(this);
 
@@ -315,7 +315,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "2.2.3.4",
@@ -325,7 +325,7 @@
                                                  5,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "6.2.3.4",
@@ -335,7 +335,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "3.3.3.4",
@@ -345,7 +345,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "3.3.4.4",
@@ -355,7 +355,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "3.3.3.4",
@@ -365,7 +365,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // test remote port
         AddTestCase(new EpcTftClassifierTestCase(c1,
@@ -377,7 +377,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -387,7 +387,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -397,7 +397,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -407,7 +407,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -417,7 +417,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -427,7 +427,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -437,7 +437,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // test local port
         AddTestCase(new EpcTftClassifierTestCase(c1,
@@ -449,7 +449,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -459,7 +459,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -469,7 +469,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -479,7 +479,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -489,7 +489,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -499,7 +499,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -509,7 +509,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -519,7 +519,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -529,7 +529,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c1,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -539,7 +539,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         ///////////////////////////
         // check default TFT
@@ -561,7 +561,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "2.2.3.4",
@@ -571,7 +571,7 @@
                                                  5,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "6.2.3.4",
@@ -581,7 +581,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "3.3.3.4",
@@ -591,7 +591,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "3.3.4.4",
@@ -601,7 +601,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "3.3.3.4",
@@ -611,7 +611,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // test remote port
         AddTestCase(new EpcTftClassifierTestCase(c2,
@@ -623,7 +623,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -633,7 +633,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -643,7 +643,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -653,7 +653,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -663,7 +663,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -673,7 +673,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -683,7 +683,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // test local port
         AddTestCase(new EpcTftClassifierTestCase(c2,
@@ -695,7 +695,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -705,7 +705,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -715,7 +715,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -725,7 +725,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -735,7 +735,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c2,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -745,7 +745,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         ///////////////////////////////////////////
         // check default TFT plus dedicated ones
@@ -768,7 +768,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "2.2.3.4",
@@ -778,7 +778,7 @@
                                                  5,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "6.2.3.4",
@@ -788,7 +788,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "3.3.3.4",
@@ -798,7 +798,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "3.3.4.4",
@@ -808,7 +808,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "3.3.3.4",
@@ -818,7 +818,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // test remote port
         AddTestCase(new EpcTftClassifierTestCase(c3,
@@ -830,7 +830,7 @@
                                                  0,
                                                  3,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -840,7 +840,7 @@
                                                  0,
                                                  3,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -850,7 +850,7 @@
                                                  0,
                                                  3,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -860,7 +860,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -870,7 +870,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -880,7 +880,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -890,7 +890,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // test local port
         AddTestCase(new EpcTftClassifierTestCase(c3,
@@ -902,7 +902,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -912,7 +912,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -922,7 +922,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -932,7 +932,7 @@
                                                  0,
                                                  3,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -942,7 +942,7 @@
                                                  0,
                                                  3,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c3,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -952,7 +952,7 @@
                                                  0,
                                                  3,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         ///////////////////////////////////////////
         // check two TFTs with different ports
@@ -974,7 +974,7 @@
                                                  0,
                                                  0,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c4,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -984,7 +984,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c4,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -994,7 +994,7 @@
                                                  0,
                                                  1,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c4,
                                                  EpcTft::UPLINK,
                                                  "9.1.1.1",
@@ -1004,7 +1004,7 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new EpcTftClassifierTestCase(c4,
                                                  EpcTft::DOWNLINK,
                                                  "9.1.1.1",
@@ -1014,6 +1014,6 @@
                                                  0,
                                                  2,
                                                  useIpv6),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-antenna.cc ns-3.42/src/lte/test/test-lte-antenna.cc
--- ns-3.41/src/lte/test/test-lte-antenna.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-antenna.cc	2024-05-29 15:29:47.128073700 -0700
@@ -273,39 +273,51 @@
 };
 
 LteAntennaTestSuite::LteAntennaTestSuite()
-    : TestSuite("lte-antenna", SYSTEM)
+    : TestSuite("lte-antenna", Type::SYSTEM)
 {
     NS_LOG_FUNCTION(this);
 
     //                                      orientation beamwidth     x            y         gain
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, 1.0, 0.0, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, 1.0, 1.0, -3.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, 1.0, -1.0, -3.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, -1.0, -1.0, -36.396), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, -1.0, -0.0, -1414.6), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, -1.0, 1.0, -36.396), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(45.0, 90.0, 1.0, 1.0, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-45.0, 90.0, 1.0, -1.0, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(90.0, 90.0, 1.0, 1.0, -3.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-90.0, 90.0, 1.0, -1.0, -3.0), TestCase::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, 1.0, 0.0, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, 1.0, 1.0, -3.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, 1.0, -1.0, -3.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, -1.0, -1.0, -36.396),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, -1.0, -0.0, -1414.6),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 90.0, -1.0, 1.0, -36.396),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(45.0, 90.0, 1.0, 1.0, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-45.0, 90.0, 1.0, -1.0, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(90.0, 90.0, 1.0, 1.0, -3.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-90.0, 90.0, 1.0, -1.0, -3.0), TestCase::Duration::QUICK);
 
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, 1.0, 0.0, 0.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, 0.5, sin(M_PI / 3), -3.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, 0.5, -sin(M_PI / 3), -3.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, -1.0, -2.0, -13.410), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, -1.0, 1.0, -20.034), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(60.0, 120.0, 0.5, sin(M_PI / 3), 0.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-60.0, 120.0, 0.5, -sin(M_PI / 3), 0.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-60.0, 120.0, 0.5, -sin(M_PI / 3), 0.0), TestCase::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, 1.0, 0.0, 0.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, 0.5, sin(M_PI / 3), -3.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, 0.5, -sin(M_PI / 3), -3.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, -1.0, -2.0, -13.410),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(0.0, 120.0, -1.0, 1.0, -20.034),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(60.0, 120.0, 0.5, sin(M_PI / 3), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-60.0, 120.0, 0.5, -sin(M_PI / 3), 0.0),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-60.0, 120.0, 0.5, -sin(M_PI / 3), 0.0),
+                TestCase::Duration::QUICK);
     AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, -0.5, -sin(M_PI / 3), 0.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 0.5, -sin(M_PI / 3), -3.0),
-                TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, -1, 0, -3.0), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, -1, 2, -15.578), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 1, 0, -14.457), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 1, 2, -73.154), TestCase::QUICK);
-    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 1, -0.1, -12.754), TestCase::QUICK);
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, -1, 0, -3.0), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, -1, 2, -15.578),
+                TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 1, 0, -14.457), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 1, 2, -73.154), TestCase::Duration::QUICK);
+    AddTestCase(new LteEnbAntennaTestCase(-120.0, 120.0, 1, -0.1, -12.754),
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-epc-e2e-data.cc ns-3.42/src/lte/test/test-lte-epc-e2e-data.cc
--- ns-3.41/src/lte/test/test-lte-epc-e2e-data.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-epc-e2e-data.cc	2024-05-29 15:29:47.128073700 -0700
@@ -380,7 +380,7 @@
 } g_lteEpcE2eDataTestSuite; ///< the test suite
 
 LteEpcE2eDataTestSuite::LteEpcE2eDataTestSuite()
-    : TestSuite("lte-epc-e2e-data", SYSTEM)
+    : TestSuite("lte-epc-e2e-data", Type::SYSTEM)
 {
     std::vector<EnbTestData> v1;
     EnbTestData e1;
@@ -389,7 +389,7 @@
     u1.bearers.push_back(f1);
     e1.ues.push_back(u1);
     v1.push_back(e1);
-    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE", v1), TestCase::QUICK);
+    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE", v1), TestCase::Duration::QUICK);
 
     std::vector<EnbTestData> v2;
     EnbTestData e2;
@@ -402,12 +402,12 @@
     u2_2.bearers.push_back(f2_2);
     e2.ues.push_back(u2_2);
     v2.push_back(e2);
-    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 2UEs", v2), TestCase::EXTENSIVE);
+    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 2UEs", v2), TestCase::Duration::EXTENSIVE);
 
     std::vector<EnbTestData> v3;
     v3.push_back(e1);
     v3.push_back(e2);
-    AddTestCase(new LteEpcE2eDataTestCase("2 eNBs", v3), TestCase::EXTENSIVE);
+    AddTestCase(new LteEpcE2eDataTestCase("2 eNBs", v3), TestCase::Duration::EXTENSIVE);
 
     EnbTestData e4;
     UeTestData u4_1;
@@ -426,7 +426,7 @@
     v4.push_back(e4);
     v4.push_back(e1);
     v4.push_back(e2);
-    AddTestCase(new LteEpcE2eDataTestCase("3 eNBs", v4), TestCase::EXTENSIVE);
+    AddTestCase(new LteEpcE2eDataTestCase("3 eNBs", v4), TestCase::Duration::EXTENSIVE);
 
     EnbTestData e5;
     UeTestData u5;
@@ -436,7 +436,7 @@
     std::vector<EnbTestData> v5;
     v5.push_back(e5);
     AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with 1000 byte packets", v5),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     EnbTestData e6;
     UeTestData u6;
@@ -446,7 +446,7 @@
     std::vector<EnbTestData> v6;
     v6.push_back(e6);
     AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with 1400 byte packets", v6),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     EnbTestData e7;
     UeTestData u7;
@@ -457,7 +457,8 @@
     e7.ues.push_back(u7);
     std::vector<EnbTestData> v7;
     v7.push_back(e7);
-    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with 2 bearers", v7), TestCase::EXTENSIVE);
+    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with 2 bearers", v7),
+                TestCase::Duration::EXTENSIVE);
 
     EnbTestData e8;
     UeTestData u8;
@@ -467,7 +468,7 @@
     std::vector<EnbTestData> v8;
     v8.push_back(e8);
     AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with fragmentation", v8),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
     EnbTestData e9;
     UeTestData u9;
@@ -476,5 +477,6 @@
     e9.ues.push_back(u9);
     std::vector<EnbTestData> v9;
     v9.push_back(e9);
-    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with aggregation", v9), TestCase::EXTENSIVE);
+    AddTestCase(new LteEpcE2eDataTestCase("1 eNB, 1UE with aggregation", v9),
+                TestCase::Duration::EXTENSIVE);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-handover-delay.cc ns-3.42/src/lte/test/test-lte-handover-delay.cc
--- ns-3.41/src/lte/test/test-lte-handover-delay.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-handover-delay.cc	2024-05-29 15:29:47.128073700 -0700
@@ -295,7 +295,7 @@
 {
   public:
     LteHandoverDelayTestSuite()
-        : TestSuite("lte-handover-delay", TestSuite::SYSTEM)
+        : TestSuite("lte-handover-delay", Type::SYSTEM)
     {
         // LogComponentEnable ("LteHandoverDelayTest", LOG_PREFIX_TIME);
         // LogComponentEnable ("LteHandoverDelayTest", LOG_DEBUG);
@@ -309,13 +309,13 @@
             // arguments: useIdealRrc, handoverTime, delayThreshold, simulationDuration
             AddTestCase(
                 new LteHandoverDelayTestCase(1, true, handoverTime, Seconds(0.005), Seconds(0.200)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new LteHandoverDelayTestCase(2, true, handoverTime, Seconds(0.005), Seconds(0.200)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
             AddTestCase(
                 new LteHandoverDelayTestCase(4, true, handoverTime, Seconds(0.005), Seconds(0.200)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
         }
 
         // HANDOVER DELAY TEST CASES WITH REAL RRC (THRESHOLD = 0.020 sec)
@@ -329,19 +329,19 @@
                                                      handoverTime,
                                                      Seconds(0.020),
                                                      Seconds(0.200)),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new LteHandoverDelayTestCase(2,
                                                      false,
                                                      handoverTime,
                                                      Seconds(0.020),
                                                      Seconds(0.200)),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new LteHandoverDelayTestCase(4,
                                                      false,
                                                      handoverTime,
                                                      Seconds(0.020),
                                                      Seconds(0.200)),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
         }
     }
 } g_lteHandoverDelayTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-handover-failure.cc ns-3.42/src/lte/test/test-lte-handover-failure.cc
--- ns-3.41/src/lte/test/test-lte-handover-failure.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-handover-failure.cc	2024-05-29 15:29:47.128073700 -0700
@@ -373,7 +373,7 @@
 {
   public:
     LteHandoverFailureTestSuite()
-        : TestSuite("lte-handover-failure", TestSuite::SYSTEM)
+        : TestSuite("lte-handover-failure", Type::SYSTEM)
     {
         // Argument sequence for all test cases: useIdealRrc, handoverTime, simulationDuration,
         // numberOfRaPreambles, preambleTransMax, raResponseWindowSize,
@@ -391,7 +391,7 @@
                                                    MilliSeconds(200),
                                                    MilliSeconds(500),
                                                    2500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to non-allocation of non-contention preamble at "
                         "target eNodeB due to max number reached",
@@ -404,7 +404,7 @@
                         MilliSeconds(200),
                         MilliSeconds(500),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to HANDOVER JOINING timeout before reception of "
                         "RRC CONNECTION RECONFIGURATION at source eNodeB",
@@ -417,7 +417,7 @@
                         MilliSeconds(0),
                         MilliSeconds(500),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to HANDOVER JOINING timeout before completion "
                         "of non-contention RACH process to target eNodeB",
@@ -430,7 +430,7 @@
                         MilliSeconds(15),
                         MilliSeconds(500),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to HANDOVER JOINING timeout before reception of "
                         "RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
@@ -443,7 +443,7 @@
                         MilliSeconds(18),
                         MilliSeconds(500),
                         500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to HANDOVER LEAVING timeout before reception of "
                         "RRC CONNECTION RECONFIGURATION at source eNodeB",
@@ -456,7 +456,7 @@
                         MilliSeconds(200),
                         MilliSeconds(0),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to HANDOVER LEAVING timeout before completion "
                         "of non-contention RACH process to target eNodeB",
@@ -469,7 +469,7 @@
                         MilliSeconds(200),
                         MilliSeconds(15),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "REAL Handover failure due to HANDOVER LEAVING timeout before reception of "
                         "RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
@@ -482,7 +482,7 @@
                         MilliSeconds(200),
                         MilliSeconds(18),
                         500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         // Test cases for IDEAL RRC protocol
         AddTestCase(new LteHandoverFailureTestCase("IDEAL Handover failure due to maximum RACH "
@@ -496,7 +496,7 @@
                                                    MilliSeconds(200),
                                                    MilliSeconds(500),
                                                    1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to non-allocation of non-contention preamble "
                         "at target eNodeB due to max number reached",
@@ -509,7 +509,7 @@
                         MilliSeconds(200),
                         MilliSeconds(500),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to HANDOVER JOINING timeout before reception "
                         "of RRC CONNECTION RECONFIGURATION at source eNodeB",
@@ -522,7 +522,7 @@
                         MilliSeconds(0),
                         MilliSeconds(500),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to HANDOVER JOINING timeout before completion "
                         "of non-contention RACH process to target eNodeB",
@@ -535,7 +535,7 @@
                         MilliSeconds(10),
                         MilliSeconds(500),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to HANDOVER JOINING timeout before reception "
                         "of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
@@ -548,7 +548,7 @@
                         MilliSeconds(4),
                         MilliSeconds(500),
                         500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to HANDOVER LEAVING timeout before reception "
                         "of RRC CONNECTION RECONFIGURATION at source eNodeB",
@@ -561,7 +561,7 @@
                         MilliSeconds(500),
                         MilliSeconds(0),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to HANDOVER LEAVING timeout before completion "
                         "of non-contention RACH process to target eNodeB",
@@ -574,7 +574,7 @@
                         MilliSeconds(500),
                         MilliSeconds(10),
                         1500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteHandoverFailureTestCase(
                         "IDEAL Handover failure due to HANDOVER LEAVING timeout before reception "
                         "of RRC CONNECTION RECONFIGURATION COMPLETE at target eNodeB",
@@ -587,6 +587,6 @@
                         MilliSeconds(500),
                         MilliSeconds(4),
                         500),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 } g_lteHandoverFailureTestSuite; ///< end of LteHandoverFailureTestSuite ()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-handover-target.cc ns-3.42/src/lte/test/test-lte-handover-target.cc
--- ns-3.41/src/lte/test/test-lte-handover-target.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-handover-target.cc	2024-05-29 15:29:47.128073700 -0700
@@ -391,7 +391,7 @@
 };
 
 LteHandoverTargetTestSuite::LteHandoverTargetTestSuite()
-    : TestSuite("lte-handover-target", SYSTEM)
+    : TestSuite("lte-handover-target", Type::SYSTEM)
 {
     // LogComponentEnable ("LteHandoverTargetTest", LOG_PREFIX_ALL);
     // LogComponentEnable ("LteHandoverTargetTest", LOG_LEVEL_ALL);
@@ -413,7 +413,7 @@
                                               1,
                                               3,
                                               "ns3::A2A4RsrqHandoverAlgorithm"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteHandoverTargetTestCase("4 cells and strongest cell algorithm",
                                               Vector(20, 40, 0),
                                               2,
@@ -421,7 +421,7 @@
                                               1,
                                               3,
                                               "ns3::A3RsrpHandoverAlgorithm"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     /*
      *    4 --- 5 --- 6
@@ -436,7 +436,7 @@
                                               5,
                                               2,
                                               "ns3::A2A4RsrqHandoverAlgorithm"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new LteHandoverTargetTestCase("6 cells and strongest cell algorithm",
                                               Vector(150, 90, 0),
                                               3,
@@ -444,7 +444,7 @@
                                               5,
                                               2,
                                               "ns3::A3RsrpHandoverAlgorithm"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 
 } // end of LteHandoverTargetTestSuite ()
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-rlc-header.cc ns-3.42/src/lte/test/test-lte-rlc-header.cc
--- ns-3.41/src/lte/test/test-lte-rlc-header.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-rlc-header.cc	2024-05-29 15:29:47.128073700 -0700
@@ -27,6 +27,7 @@
 #include <bitset>
 #include <iomanip>
 #include <list>
+#include <vector>
 
 NS_LOG_COMPONENT_DEFINE("TestLteRlcHeader");
 
@@ -48,13 +49,12 @@
      */
     static std::string sprintPacketContentsHex(Ptr<Packet> pkt)
     {
-        uint32_t psize = pkt->GetSize();
-        uint8_t buffer[psize];
+        std::vector<uint8_t> buffer(pkt->GetSize());
         std::ostringstream oss(std::ostringstream::out);
-        pkt->CopyData(buffer, psize);
-        for (uint32_t i = 0; i < psize; i++)
+        pkt->CopyData(buffer.data(), buffer.size());
+        for (auto b : buffer)
         {
-            oss << std::setfill('0') << std::setw(2) << std::hex << (uint32_t)buffer[i];
+            oss << std::setfill('0') << std::setw(2) << std::hex << (uint32_t)b;
         }
         return oss.str();
     }
@@ -66,13 +66,12 @@
      */
     static std::string sprintPacketContentsBin(Ptr<Packet> pkt)
     {
-        uint32_t psize = pkt->GetSize();
-        uint8_t buffer[psize];
+        std::vector<uint8_t> buffer(pkt->GetSize());
         std::ostringstream oss(std::ostringstream::out);
-        pkt->CopyData(buffer, psize);
-        for (uint32_t i = 0; i < psize; i++)
+        pkt->CopyData(buffer.data(), buffer.size());
+        for (auto b : buffer)
         {
-            oss << (std::bitset<8>(buffer[i]));
+            oss << (std::bitset<8>(b));
         }
         return std::string(oss.str() + "\n");
     }
@@ -193,7 +192,7 @@
 } staticLteRlcHeaderTestSuiteInstance; ///< the test suite
 
 LteRlcHeaderTestSuite::LteRlcHeaderTestSuite()
-    : TestSuite("lte-rlc-header", UNIT)
+    : TestSuite("lte-rlc-header", Type::UNIT)
 {
     NS_LOG_FUNCTION(this);
 
@@ -201,14 +200,14 @@
         SequenceNumber10 ackSn(8);
         std::list<SequenceNumber10> nackSnList;
         std::string hex("0020");
-        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::QUICK);
+        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::Duration::QUICK);
     }
 
     {
         SequenceNumber10 ackSn(873);
         std::list<SequenceNumber10> nackSnList;
         std::string hex("0da4");
-        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::QUICK);
+        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::Duration::QUICK);
     }
 
     {
@@ -217,7 +216,7 @@
             SequenceNumber10(873),
         };
         std::string hex("000bb480");
-        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::QUICK);
+        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::Duration::QUICK);
     }
 
     {
@@ -227,7 +226,7 @@
             SequenceNumber10(754),
         };
         std::string hex("000bfed790");
-        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::QUICK);
+        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::Duration::QUICK);
     }
 
     {
@@ -238,7 +237,7 @@
             SequenceNumber10(947),
         };
         std::string hex("000bfed795d980");
-        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::QUICK);
+        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::Duration::QUICK);
     }
 
     {
@@ -250,7 +249,7 @@
             SequenceNumber10(347),
         };
         std::string hex("000bfed795d9cad8");
-        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::QUICK);
+        AddTestCase(new RlcAmStatusPduTestCase(ackSn, nackSnList, hex), TestCase::Duration::QUICK);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-rrc.cc ns-3.42/src/lte/test/test-lte-rrc.cc
--- ns-3.41/src/lte/test/test-lte-rrc.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-rrc.cc	2024-05-29 15:29:47.128073700 -0700
@@ -773,7 +773,7 @@
 };
 
 LteRrcTestSuite::LteRrcTestSuite()
-    : TestSuite("lte-rrc", SYSTEM)
+    : TestSuite("lte-rrc", Type::SYSTEM)
 {
     //  LogComponentEnableAll (LOG_PREFIX_ALL);
     //  LogComponentEnable ("LteRrcTest", LOG_LEVEL_ALL);
@@ -790,64 +790,64 @@
         // admitRrcConnectionRequest
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 0, 0, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 0, 100, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 1, 0, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 1, 100, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 2, 0, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 2, 100, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 0, 20, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 0, 20, 10, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 0, 20, 100, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 1, 20, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 1, 20, 10, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 1, 20, 100, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 2, 20, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 2, 20, 10, 1, false, useIdealRrc, true),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 2, 20, 100, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(3, 0, 20, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(4, 0, 20, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(4, 0, 20, 300, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(20, 0, 10, 1, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(50, 0, 0, 0, 1, false, useIdealRrc, true),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
 
         // Test cases to check admitRrcConnectionRequest=false
         //                                                     nUes      tConnBase delayDiscStart
@@ -857,28 +857,28 @@
         //                                                        admitRrcConnectionRequest
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 0, 0, 0, 1, false, useIdealRrc, false),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(1, 2, 100, 0, 1, false, useIdealRrc, false),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 0, 20, 0, 1, false, useIdealRrc, false),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(2, 1, 20, 0, 1, false, useIdealRrc, false),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new LteRrcConnectionEstablishmentTestCase(3, 0, 20, 0, 1, false, useIdealRrc, false),
-            TestCase::EXTENSIVE);
+            TestCase::Duration::EXTENSIVE);
     }
 
     // Test cases with transmission error
     AddTestCase(new LteRrcConnectionEstablishmentErrorTestCase(Seconds(0.020214),
                                                                "failure at RRC Connection Request"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new LteRrcConnectionEstablishmentErrorTestCase(Seconds(0.025),
                                                                "failure at RRC Connection Setup"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     /*
      * With RLF implementation we now do support the Idle mode,
      * thus it solve Bug 1762 Comment #25.
@@ -886,7 +886,7 @@
     AddTestCase(
         new LteRrcConnectionEstablishmentErrorTestCase(Seconds(0.030),
                                                        "failure at RRC Connection Setup Complete"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-x2-handover.cc ns-3.42/src/lte/test/test-lte-x2-handover.cc
--- ns-3.41/src/lte/test/test-lte-x2-handover.cc	2024-02-09 14:44:08.341793300 -0800
+++ ns-3.42/src/lte/test/test-lte-x2-handover.cc	2024-05-29 15:29:47.128073700 -0700
@@ -673,7 +673,7 @@
 };
 
 LteX2HandoverTestSuite::LteX2HandoverTestSuite()
-    : TestSuite("lte-x2-handover", SYSTEM)
+    : TestSuite("lte-x2-handover", Type::SYSTEM)
 {
     // in the following:
     // fwd means handover from enb 0 to enb 1
@@ -772,7 +772,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   0,
                                                   handoverEventList0,
@@ -780,7 +780,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   5,
                                                   handoverEventList0,
@@ -788,7 +788,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   5,
                                                   handoverEventList0,
@@ -796,7 +796,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   0,
                                                   handoverEventList1,
@@ -804,7 +804,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   1,
                                                   handoverEventList1,
@@ -812,7 +812,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   2,
                                                   handoverEventList1,
@@ -820,7 +820,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   0,
                                                   handoverEventList1,
@@ -828,7 +828,7 @@
                                                   *schedIt,
                                                   false,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   1,
                                                   handoverEventList1,
@@ -836,7 +836,7 @@
                                                   *schedIt,
                                                   false,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   2,
                                                   handoverEventList1,
@@ -844,7 +844,7 @@
                                                   *schedIt,
                                                   false,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   0,
                                                   handoverEventList1,
@@ -852,7 +852,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   1,
                                                   handoverEventList1,
@@ -860,7 +860,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   2,
                                                   handoverEventList1,
@@ -868,7 +868,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   0,
                                                   handoverEventList1,
@@ -876,7 +876,7 @@
                                                   *schedIt,
                                                   false,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   1,
                                                   handoverEventList1,
@@ -884,7 +884,7 @@
                                                   *schedIt,
                                                   false,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   2,
                                                   handoverEventList1,
@@ -892,7 +892,7 @@
                                                   *schedIt,
                                                   false,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   0,
                                                   handoverEventList2,
@@ -900,7 +900,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   1,
                                                   handoverEventList2,
@@ -908,7 +908,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   2,
                                                   handoverEventList2,
@@ -916,7 +916,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   0,
                                                   handoverEventList3,
@@ -924,7 +924,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   1,
                                                   handoverEventList3,
@@ -932,7 +932,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(1,
                                                   2,
                                                   handoverEventList3,
@@ -940,7 +940,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   0,
                                                   handoverEventList3,
@@ -948,7 +948,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   1,
                                                   handoverEventList3,
@@ -956,7 +956,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   2,
                                                   handoverEventList3,
@@ -964,7 +964,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   0,
                                                   handoverEventList4,
@@ -972,7 +972,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   1,
                                                   handoverEventList4,
@@ -980,7 +980,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   2,
                                                   handoverEventList4,
@@ -988,7 +988,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   0,
                                                   handoverEventList5,
@@ -996,7 +996,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   1,
                                                   handoverEventList5,
@@ -1004,7 +1004,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(2,
                                                   2,
                                                   handoverEventList5,
@@ -1012,7 +1012,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   0,
                                                   handoverEventList3,
@@ -1020,7 +1020,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   1,
                                                   handoverEventList3,
@@ -1028,7 +1028,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   2,
                                                   handoverEventList3,
@@ -1036,7 +1036,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   0,
                                                   handoverEventList4,
@@ -1044,7 +1044,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   1,
                                                   handoverEventList4,
@@ -1052,7 +1052,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   2,
                                                   handoverEventList4,
@@ -1060,7 +1060,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   0,
                                                   handoverEventList5,
@@ -1068,7 +1068,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   1,
                                                   handoverEventList5,
@@ -1076,7 +1076,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::EXTENSIVE);
+                        TestCase::Duration::EXTENSIVE);
             AddTestCase(new LteX2HandoverTestCase(3,
                                                   2,
                                                   handoverEventList5,
@@ -1084,7 +1084,7 @@
                                                   *schedIt,
                                                   true,
                                                   useIdealRrc),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
         }
     }
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/lte/test/test-lte-x2-handover-measures.cc ns-3.42/src/lte/test/test-lte-x2-handover-measures.cc
--- ns-3.41/src/lte/test/test-lte-x2-handover-measures.cc	2024-02-09 14:44:08.337793000 -0800
+++ ns-3.42/src/lte/test/test-lte-x2-handover-measures.cc	2024-05-29 15:29:47.128073700 -0700
@@ -749,7 +749,7 @@
 };
 
 LteX2HandoverMeasuresTestSuite::LteX2HandoverMeasuresTestSuite()
-    : TestSuite("lte-x2-handover-measures", SYSTEM)
+    : TestSuite("lte-x2-handover-measures", Type::SYSTEM)
 {
     Time checkInterval = Seconds(1);
 
@@ -789,7 +789,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(2,
                                                       1,
                                                       1,
@@ -800,7 +800,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteX2HandoverMeasuresTestCase(2,
                                                       1,
                                                       2,
@@ -811,7 +811,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(3,
                                                       1,
                                                       0,
@@ -822,7 +822,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(3,
                                                       1,
                                                       1,
@@ -833,7 +833,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(3,
                                                       1,
                                                       2,
@@ -844,7 +844,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::EXTENSIVE);
+                    TestCase::Duration::EXTENSIVE);
         AddTestCase(new LteX2HandoverMeasuresTestCase(4,
                                                       1,
                                                       0,
@@ -855,7 +855,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::EXTENSIVE);
+                    TestCase::Duration::EXTENSIVE);
         AddTestCase(new LteX2HandoverMeasuresTestCase(4,
                                                       1,
                                                       1,
@@ -866,7 +866,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(4,
                                                       1,
                                                       2,
@@ -877,7 +877,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
     }
 
     sched = "ns3::RrFfMacScheduler";
@@ -894,7 +894,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::EXTENSIVE);
+                    TestCase::Duration::EXTENSIVE);
         AddTestCase(new LteX2HandoverMeasuresTestCase(3,
                                                       1,
                                                       0,
@@ -905,7 +905,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(4,
                                                       1,
                                                       0,
@@ -916,7 +916,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
     }
 
     ho = "ns3::A3RsrpHandoverAlgorithm";
@@ -934,7 +934,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::EXTENSIVE);
+                    TestCase::Duration::EXTENSIVE);
         AddTestCase(new LteX2HandoverMeasuresTestCase(3,
                                                       1,
                                                       0,
@@ -945,7 +945,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(4,
                                                       1,
                                                       0,
@@ -956,7 +956,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
     }
 
     sched = "ns3::RrFfMacScheduler";
@@ -973,7 +973,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new LteX2HandoverMeasuresTestCase(3,
                                                       1,
                                                       0,
@@ -984,7 +984,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::TAKES_FOREVER);
+                    TestCase::Duration::TAKES_FOREVER);
         AddTestCase(new LteX2HandoverMeasuresTestCase(4,
                                                       1,
                                                       0,
@@ -995,7 +995,7 @@
                                                       ho,
                                                       true,
                                                       useIdealRrc),
-                    TestCase::EXTENSIVE);
+                    TestCase::Duration::EXTENSIVE);
     }
 
 } // end of LteX2HandoverMeasuresTestSuite ()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/doc/Makefile ns-3.42/src/mesh/doc/Makefile
--- ns-3.41/src/mesh/doc/Makefile	2024-02-09 14:44:08.341793300 -0800
+++ ns-3.42/src/mesh/doc/Makefile	2024-05-29 15:29:47.128073700 -0700
@@ -41,7 +41,7 @@
 
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/helper/mesh-helper.cc ns-3.42/src/mesh/helper/mesh-helper.cc
--- ns-3.41/src/mesh/helper/mesh-helper.cc	2024-02-09 14:44:08.341793300 -0800
+++ ns-3.42/src/mesh/helper/mesh-helper.cc	2024-05-29 15:29:47.128073700 -0700
@@ -27,6 +27,7 @@
 #include "ns3/minstrel-wifi-manager.h"
 #include "ns3/pointer.h"
 #include "ns3/simulator.h"
+#include "ns3/string.h"
 #include "ns3/wifi-default-ack-manager.h"
 #include "ns3/wifi-default-protection-manager.h"
 #include "ns3/wifi-helper.h"
@@ -120,6 +121,13 @@
     // this is a const method, but we need to force the correct QoS setting
     ObjectFactory macObjectFactory = m_mac;
     macObjectFactory.Set("QosSupported", BooleanValue(true)); // a mesh station is a QoS station
+    // create (Qos)Txop objects
+    for (const std::string ac : {"BE", "BK", "VI", "VO"})
+    {
+        auto qosTxop =
+            CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue(std::string("AC_") + ac));
+        macObjectFactory.Set(ac + "_Txop", PointerValue(qosTxop));
+    }
     std::vector<Ptr<WifiPhy>> phys = phyHelper.Create(node, device);
     NS_ABORT_IF(phys.size() != 1);
     node->AddDevice(device);
@@ -135,18 +143,19 @@
     mac->SetAddress(Mac48Address::Allocate());
     device->SetMac(mac);
     mac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
-    mac->ConfigureStandard(m_standard);
-    Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager();
-    if (fem)
-    {
-        Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager>();
-        protectionManager->SetWifiMac(mac);
-        fem->SetProtectionManager(protectionManager);
-
-        Ptr<WifiAckManager> ackManager = CreateObject<WifiDefaultAckManager>();
-        ackManager->SetWifiMac(mac);
-        fem->SetAckManager(ackManager);
-    }
+    mac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    ObjectFactory femFactory;
+    femFactory.SetTypeId(GetFrameExchangeManagerTypeIdName(m_standard, true));
+    auto fem = femFactory.Create<FrameExchangeManager>();
+    mac->SetFrameExchangeManagers({fem});
+    fem->SetAddress(mac->GetAddress());
+    Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager>();
+    protectionManager->SetWifiMac(mac);
+    fem->SetProtectionManager(protectionManager);
+
+    Ptr<WifiAckManager> ackManager = CreateObject<WifiDefaultAckManager>();
+    ackManager->SetWifiMac(mac);
+    fem->SetAckManager(ackManager);
     mac->SwitchFrequencyChannel(channelId);
 
     return device;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/model/dot11s/hwmp-protocol-mac.cc ns-3.42/src/mesh/model/dot11s/hwmp-protocol-mac.cc
--- ns-3.41/src/mesh/model/dot11s/hwmp-protocol-mac.cc	2024-02-09 14:44:08.341793300 -0800
+++ ns-3.42/src/mesh/model/dot11s/hwmp-protocol-mac.cc	2024-05-29 15:29:47.128073700 -0700
@@ -321,7 +321,7 @@
 HwmpProtocolMac::SendMyPreq()
 {
     NS_LOG_FUNCTION(this);
-    if (m_preqTimer.IsRunning())
+    if (m_preqTimer.IsPending())
     {
         return;
     }
@@ -330,7 +330,7 @@
         return;
     }
     // reschedule sending PREQ
-    NS_ASSERT(!m_preqTimer.IsRunning());
+    NS_ASSERT(!m_preqTimer.IsPending());
     m_preqTimer =
         Simulator::Schedule(m_protocol->GetPreqMinInterval(), &HwmpProtocolMac::SendMyPreq, this);
     SendPreqVector(m_myPreq);
@@ -466,7 +466,7 @@
 HwmpProtocolMac::SendMyPerr()
 {
     NS_LOG_FUNCTION(this);
-    if (m_perrTimer.IsRunning())
+    if (m_perrTimer.IsPending())
     {
         return;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/model/dot11s/ie-dot11s-id.h ns-3.42/src/mesh/model/dot11s/ie-dot11s-id.h
--- ns-3.41/src/mesh/model/dot11s/ie-dot11s-id.h	2024-02-09 14:44:08.341793300 -0800
+++ ns-3.42/src/mesh/model/dot11s/ie-dot11s-id.h	2024-05-29 15:29:47.128073700 -0700
@@ -32,7 +32,6 @@
 
 /**
  * \brief a IEEE 802.11 Mesh ID element (Section 8.4.2.101 of IEEE 802.11-2012)
- * \see attribute_IeMeshId
  */
 class IeMeshId : public WifiInformationElement
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/model/mesh-point-device.cc ns-3.42/src/mesh/model/mesh-point-device.cc
--- ns-3.41/src/mesh/model/mesh-point-device.cc	2024-02-09 14:44:08.357793300 -0800
+++ ns-3.42/src/mesh/model/mesh-point-device.cc	2024-05-29 15:29:47.132073600 -0700
@@ -273,7 +273,7 @@
 MeshPointDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION(this);
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/model/mesh-wifi-interface-mac.cc ns-3.42/src/mesh/model/mesh-wifi-interface-mac.cc
--- ns-3.41/src/mesh/model/mesh-wifi-interface-mac.cc	2024-02-09 14:44:08.357793300 -0800
+++ ns-3.42/src/mesh/model/mesh-wifi-interface-mac.cc	2024-05-29 15:29:47.132073600 -0700
@@ -32,6 +32,7 @@
 #include "ns3/random-variable-stream.h"
 #include "ns3/simulator.h"
 #include "ns3/socket.h"
+#include "ns3/string.h"
 #include "ns3/trace-source-accessor.h"
 #include "ns3/wifi-mac-queue-scheduler.h"
 #include "ns3/wifi-mac-queue.h"
@@ -75,7 +76,6 @@
 }
 
 MeshWifiInterfaceMac::MeshWifiInterfaceMac()
-    : m_standard(WIFI_STANDARD_80211a)
 {
     NS_LOG_FUNCTION(this);
 
@@ -149,7 +149,7 @@
     {
         Time randomStart = Seconds(m_coefficient->GetValue());
         // Now start sending beacons after some random delay (to avoid collisions)
-        NS_ASSERT(!m_beaconSendEvent.IsRunning());
+        NS_ASSERT(!m_beaconSendEvent.IsPending());
         m_beaconSendEvent =
             Simulator::Schedule(randomStart, &MeshWifiInterfaceMac::SendBeacon, this);
         m_tbtt = Simulator::Now() + randomStart;
@@ -165,7 +165,7 @@
 MeshWifiInterfaceMac::AssignStreams(int64_t stream)
 {
     NS_LOG_FUNCTION(this << stream);
-    int64_t currentStream = stream;
+    int64_t currentStream = stream + WifiMac::AssignStreams(stream);
     m_coefficient->SetStream(currentStream++);
     for (auto i = m_plugins.begin(); i < m_plugins.end(); i++)
     {
@@ -387,7 +387,7 @@
 bool
 MeshWifiInterfaceMac::GetBeaconGeneration() const
 {
-    return m_beaconSendEvent.IsRunning();
+    return m_beaconSendEvent.IsPending();
 }
 
 Time
@@ -423,7 +423,7 @@
     NS_LOG_FUNCTION(this);
     NS_LOG_DEBUG(GetAddress() << " is sending beacon");
 
-    NS_ASSERT(!m_beaconSendEvent.IsRunning());
+    NS_ASSERT(!m_beaconSendEvent.IsPending());
 
     // Form & send beacon
     MeshWifiBeacon beacon(GetSsid(), GetSupportedRates(), m_beaconInterval.GetMicroSeconds());
@@ -597,11 +597,9 @@
 }
 
 void
-MeshWifiInterfaceMac::ConfigureStandard(WifiStandard standard)
+MeshWifiInterfaceMac::DoCompleteConfig()
 {
     NS_ABORT_IF(!GetQosSupported());
-    WifiMac::ConfigureStandard(standard);
-    m_standard = standard;
 }
 
 void
@@ -611,7 +609,7 @@
     // We use the single DCF provided by WifiMac for the purpose of
     // Beacon transmission. For this we need to reconfigure the channel
     // access parameters slightly, and do so here.
-    m_txop = CreateObject<Txop>();
+    m_txop = CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"));
     m_txop->SetWifiMac(this);
     GetLink(0).channelAccessManager->Add(m_txop);
     m_txop->SetTxMiddle(m_txMiddle);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/model/mesh-wifi-interface-mac.h ns-3.42/src/mesh/model/mesh-wifi-interface-mac.h
--- ns-3.41/src/mesh/model/mesh-wifi-interface-mac.h	2024-02-09 14:44:08.357793300 -0800
+++ ns-3.42/src/mesh/model/mesh-wifi-interface-mac.h	2024-05-29 15:29:47.132073600 -0700
@@ -205,12 +205,6 @@
      */
     void SetBeaconGeneration(bool enable);
     /**
-     * Finish configuration based on the WifiStandard being provided
-     *
-     * \param standard the WifiStandard being configured
-     */
-    void ConfigureStandard(WifiStandard standard) override;
-    /**
      * \param cwMin the minimum contention window size
      * \param cwMax the maximum contention window size
      *
@@ -227,9 +221,11 @@
      * \param stream first stream index to use
      * \return the number of stream indices assigned by this model
      */
-    int64_t AssignStreams(int64_t stream);
+    int64_t AssignStreams(int64_t stream) override;
 
   private:
+    void DoCompleteConfig() override;
+
     /**
      * Frame receive handler
      *
@@ -313,9 +309,6 @@
 
     Statistics m_stats; ///< statistics
 
-    /// Current standard: needed to configure metric
-    WifiStandard m_standard;
-
     /// Add randomness to beacon generation
     Ptr<UniformRandomVariable> m_coefficient;
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/test/dot11s/dot11s-test-suite.cc ns-3.42/src/mesh/test/dot11s/dot11s-test-suite.cc
--- ns-3.41/src/mesh/test/dot11s/dot11s-test-suite.cc	2024-02-09 14:44:08.357793300 -0800
+++ ns-3.42/src/mesh/test/dot11s/dot11s-test-suite.cc	2024-05-29 15:29:47.132073600 -0700
@@ -285,11 +285,11 @@
 };
 
 Dot11sTestSuite::Dot11sTestSuite()
-    : TestSuite("devices-mesh-dot11s", UNIT)
+    : TestSuite("devices-mesh-dot11s", Type::UNIT)
 {
-    AddTestCase(new MeshHeaderTest, TestCase::QUICK);
-    AddTestCase(new HwmpRtableTest, TestCase::QUICK);
-    AddTestCase(new PeerLinkFrameStartTest, TestCase::QUICK);
+    AddTestCase(new MeshHeaderTest, TestCase::Duration::QUICK);
+    AddTestCase(new HwmpRtableTest, TestCase::Duration::QUICK);
+    AddTestCase(new PeerLinkFrameStartTest, TestCase::Duration::QUICK);
 }
 
 static Dot11sTestSuite g_dot11sTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/test/dot11s/regression.cc ns-3.42/src/mesh/test/dot11s/regression.cc
--- ns-3.41/src/mesh/test/dot11s/regression.cc	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mesh/test/dot11s/regression.cc	2024-05-29 15:29:47.132073600 -0700
@@ -36,15 +36,15 @@
 {
   public:
     Dot11sRegressionSuite()
-        : TestSuite("devices-mesh-dot11s-regression", SYSTEM)
+        : TestSuite("devices-mesh-dot11s-regression", Type::SYSTEM)
     {
         // We do not use NS_TEST_SOURCEDIR variable here since mesh/test has
         // subdirectories
         SetDataDir(std::string("src/mesh/test/dot11s"));
-        AddTestCase(new PeerManagementProtocolRegressionTest, TestCase::QUICK);
-        AddTestCase(new HwmpSimplestRegressionTest, TestCase::QUICK);
-        AddTestCase(new HwmpReactiveRegressionTest, TestCase::QUICK);
-        AddTestCase(new HwmpProactiveRegressionTest, TestCase::QUICK);
-        AddTestCase(new HwmpDoRfRegressionTest, TestCase::QUICK);
+        AddTestCase(new PeerManagementProtocolRegressionTest, TestCase::Duration::QUICK);
+        AddTestCase(new HwmpSimplestRegressionTest, TestCase::Duration::QUICK);
+        AddTestCase(new HwmpReactiveRegressionTest, TestCase::Duration::QUICK);
+        AddTestCase(new HwmpProactiveRegressionTest, TestCase::Duration::QUICK);
+        AddTestCase(new HwmpDoRfRegressionTest, TestCase::Duration::QUICK);
     }
 } g_dot11sRegressionSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/test/flame/flame-test-suite.cc ns-3.42/src/mesh/test/flame/flame-test-suite.cc
--- ns-3.41/src/mesh/test/flame/flame-test-suite.cc	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mesh/test/flame/flame-test-suite.cc	2024-05-29 15:29:47.136073600 -0700
@@ -151,10 +151,10 @@
 };
 
 FlameTestSuite::FlameTestSuite()
-    : TestSuite("devices-mesh-flame", UNIT)
+    : TestSuite("devices-mesh-flame", Type::UNIT)
 {
-    AddTestCase(new FlameHeaderTest, TestCase::QUICK);
-    AddTestCase(new FlameRtableTest, TestCase::QUICK);
+    AddTestCase(new FlameHeaderTest, TestCase::Duration::QUICK);
+    AddTestCase(new FlameRtableTest, TestCase::Duration::QUICK);
 }
 
 static FlameTestSuite g_flameTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/test/flame/regression.cc ns-3.42/src/mesh/test/flame/regression.cc
--- ns-3.41/src/mesh/test/flame/regression.cc	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mesh/test/flame/regression.cc	2024-05-29 15:29:47.136073600 -0700
@@ -32,11 +32,11 @@
 {
   public:
     FlameRegressionSuite()
-        : TestSuite("devices-mesh-flame-regression", SYSTEM)
+        : TestSuite("devices-mesh-flame-regression", Type::SYSTEM)
     {
         // We do not use NS_TEST_SOURCEDIR variable here since mesh/test has
         // subdirectories
         SetDataDir(std::string("src/mesh/test/flame"));
-        AddTestCase(new FlameRegressionTest, TestCase::QUICK);
+        AddTestCase(new FlameRegressionTest, TestCase::Duration::QUICK);
     }
 } g_flameRegressionSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mesh/test/mesh-information-element-vector-test-suite.cc ns-3.42/src/mesh/test/mesh-information-element-vector-test-suite.cc
--- ns-3.41/src/mesh/test/mesh-information-element-vector-test-suite.cc	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mesh/test/mesh-information-element-vector-test-suite.cc	2024-05-29 15:29:47.136073600 -0700
@@ -162,9 +162,9 @@
 };
 
 MeshTestSuite::MeshTestSuite()
-    : TestSuite("devices-mesh", UNIT)
+    : TestSuite("devices-mesh", Type::UNIT)
 {
-    AddTestCase(new MeshInformationElementVectorBist, TestCase::QUICK);
+    AddTestCase(new MeshInformationElementVectorBist, TestCase::Duration::QUICK);
 }
 
 static MeshTestSuite g_meshTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/CMakeLists.txt ns-3.42/src/mobility/CMakeLists.txt
--- ns-3.41/src/mobility/CMakeLists.txt	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mobility/CMakeLists.txt	2024-05-29 15:29:47.136073600 -0700
@@ -10,6 +10,7 @@
     model/constant-velocity-helper.cc
     model/constant-velocity-mobility-model.cc
     model/gauss-markov-mobility-model.cc
+    model/geocentric-constant-position-mobility-model.cc
     model/geographic-positions.cc
     model/hierarchical-mobility-model.cc
     model/mobility-model.cc
@@ -31,6 +32,7 @@
     model/constant-velocity-helper.h
     model/constant-velocity-mobility-model.h
     model/gauss-markov-mobility-model.h
+    model/geocentric-constant-position-mobility-model.h
     model/geographic-positions.h
     model/hierarchical-mobility-model.h
     model/mobility-model.h
@@ -42,10 +44,12 @@
     model/steady-state-random-waypoint-mobility-model.h
     model/waypoint-mobility-model.h
     model/waypoint.h
-  LIBRARIES_TO_LINK ${libnetwork}
+  LIBRARIES_TO_LINK ${libantenna}
+                    ${libnetwork}
   TEST_SOURCES
     test/box-line-intersection-test.cc
     test/geo-to-cartesian-test.cc
+    test/geocentric-topocentric-conversion-test.cc
     test/mobility-test-suite.cc
     test/mobility-trace-test-suite.cc
     test/ns2-mobility-helper-test-suite.cc
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/doc/mobility.rst ns-3.42/src/mobility/doc/mobility.rst
--- ns-3.41/src/mobility/doc/mobility.rst	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mobility/doc/mobility.rst	2024-05-29 15:29:47.136073600 -0700
@@ -52,26 +52,30 @@
 #################
 
 There are many possible coordinate systems and possible translations between
-them.  |ns3| uses the Cartesian coordinate system only, at present.
+them. Currently, |ns3| provides support for the Cartesian, Geocentric Cartesian,
+and Geographic coordinate systems, which are defined as:
+
+* **Cartesian coordinates**: They represent a point in 3D space using the set of coordinates (x,y,z).
+  This is the default coordinate system in |ns3|, and it is the most suitable for simulation scenarios whose size is in the order of a few km.
+
+  * **Topocentric coordinates**: Cartesian coordinates where a specific reference
+    point on the Earth's surface, such as lat-lon, for the origin is given.
+    This coordinate system is useful for converting to and from Geocentric/Geographic coordinates.
+
+  * **Geocentric Cartesian coordinates**: Cartesian coordinate system where the
+    origin is fixed in the Earth's center of mass. The implementation follows the description in Sec. 6.3 of [38811]_.
+
+* **Geographic coordinates**: They represent a point in 3D space by assuming it
+  is located on the surface or in the orbit of the Earth. Positions are uniquely
+  described by three values: latitude, longitude and altitude. The latter reference is the Earth's surface.
+
+At the moment, the geocentric Cartesian coordinates are adopted by the
+GeocentricConstantPositionMobilityModel only.
+This class implements the Get/SetPosition methods, which leverage the
+GeographicPosition class to offer conversions to and from Cartesian coordinates.
+Additionally, users can set the position of a node by its geographical coordinates
+via the methods Get/SetGeographicPosition.
 
-The question has arisen as to how to use the mobility models (supporting
-Cartesian coordinates) with different coordinate systems.  This is possible
-if the user performs conversion between the |ns3| Cartesian and the
-other coordinate system.  One possible library to assist is
-the `proj4 <https://proj.org>`_ library for projections and reverse
-projections.
-
-If we support converting between coordinate systems, we must adopt a
-reference.  It has been suggested to use the geocentric Cartesian coordinate
-system as a reference.  Contributions are welcome in this regard.
-
-The question has arisen about adding a new mobility model whose motion
-is natively implemented in a different coordinate system (such as an
-orbital mobility model implemented using spherical coordinate system).
-We advise to create a subclass with the APIs desired
-(such as Get/SetSphericalPosition), and new position allocators, and
-implement the motion however desired, but must also support the conversion to
-cartesian (by supporting the cartesian Get/SetPosition).
 
 Coordinates
 ###########
@@ -112,6 +116,7 @@
 - RandomWaypoint
 - SteadyStateRandomWaypoint
 - Waypoint
+- GeocentricConstantPosition
 
 PositionAllocator
 #################
@@ -198,13 +203,14 @@
 Scope and Limitations
 =====================
 
-- only cartesian coordinates are presently supported
+- Cartesian, geocentric cartesian, and geographic coordinates are presently supported
 
 References
 ==========
 
 .. [Camp2002] T. Camp, J. Boleng, V. Davies.  "A survey of mobility models for ad hoc network research",
    in Wireless Communications and Mobile Computing, 2002: vol. 2, pp. 2483-2502.
+.. [38811] 3GPP. 2018. TR 38.811, Study on New Radio (NR) to support non-terrestrial networks, V15.4.0. (2020-09).
 
 Usage
 *****
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/examples/CMakeLists.txt ns-3.42/src/mobility/examples/CMakeLists.txt
--- ns-3.41/src/mobility/examples/CMakeLists.txt	2024-02-09 14:44:08.361793300 -0800
+++ ns-3.42/src/mobility/examples/CMakeLists.txt	2024-05-29 15:29:47.136073600 -0700
@@ -1,5 +1,6 @@
 set(base_examples
     bonnmotion-ns2-example
+    constant-mobility-example
     main-random-topology
     main-random-walk
     ns2-mobility-trace
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/examples/constant-mobility-example.cc ns-3.42/src/mobility/examples/constant-mobility-example.cc
--- ns-3.41/src/mobility/examples/constant-mobility-example.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/mobility/examples/constant-mobility-example.cc	2024-05-29 15:29:47.136073600 -0700
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2024 Tokushima University, Tokushima, Japan.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
+ */
+
+/*
+   This example shows a comparison between node mobility set with and without the
+   use of helpers. Furthermore it shows a simple way to update the node positions.
+   More advanced position allocations and mobility patterns can be achieve with
+   the use of other helpers.
+
+   In this example, node N1 moves to the right in 3 different instances
+   during the simulation while node N0 remains static. A trace is used to print a
+   message when movement is detected in node N1.
+
+               10 m         {Sec 2}      10m         {Sec 4}      10 m      {Sec 6}
+   N0,N1 --------------------->N1--------------------> N1 ------------------> N1
+  (0,0,0)     Move Right    (10,0,0)   Move Right   (20,0,0)   Move Right   (30,0,0)
+*/
+
+#include <ns3/mobility-module.h>
+#include <ns3/node.h>
+#include <ns3/simulator.h>
+
+using namespace ns3;
+
+void
+CourseChangeCallback(Ptr<const MobilityModel> mobility)
+{
+    std::cout << Simulator::Now().As(Time::S) << " Movement detected (Node "
+              << mobility->GetObject<Node>()->GetId() << ")!\n";
+}
+
+void
+MoveNode(Ptr<Node> node, const Vector& pos)
+{
+    Ptr<MobilityModel> mobilityModel = node->GetObject<MobilityModel>();
+    NS_ASSERT_MSG(mobilityModel, "Node doesn't have a mobility model");
+    mobilityModel->SetPosition(pos);
+
+    Vector newPos = mobilityModel->GetPosition();
+
+    std::cout << Simulator::Now().As(Time::S) << " Node " << node->GetId() << " | MoveRight, Pos ("
+              << newPos.x << "," << newPos.y << "," << newPos.z << ")\n";
+}
+
+int
+main(int argc, char* argv[])
+{
+    // Method 1: Install the mobility model using the helper
+    //           The helper creates and installs the mobility to a single node
+    //           or multiple nodes in a node container. Different helpers might
+    //           have additional options.
+
+    NodeContainer nodeContainer(1);
+
+    MobilityHelper mobility;
+    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+
+    Ptr<ListPositionAllocator> positionAllocator = CreateObject<ListPositionAllocator>();
+    positionAllocator->Add(Vector(0, 0, 0));
+
+    mobility.SetPositionAllocator(positionAllocator);
+    Ptr<Node> n0 = nodeContainer.Get(0);
+    mobility.Install(n0);
+
+    // Method 2: Install the mobility manually
+    //           You need to manually create both, the node object and the mobility object.
+    //           After that, you aggregate the mobility to a node.
+
+    Ptr<Node> n1 = CreateObject<Node>();
+    Ptr<ConstantPositionMobilityModel> mob1 = CreateObject<ConstantPositionMobilityModel>();
+    n1->AggregateObject(mob1);
+    mob1->SetPosition(Vector(0, 0, 0));
+
+    // Set the mobility trace hook to node n1 to keep track of its movements
+    mob1->TraceConnectWithoutContext("CourseChange", MakeBoundCallback(&CourseChangeCallback));
+
+    // Schedule movements to node n1
+    Simulator::ScheduleWithContext(n1->GetId(), Seconds(2.0), &MoveNode, n1, Vector(10, 0, 0));
+
+    Simulator::ScheduleWithContext(n1->GetId(), Seconds(4.0), &MoveNode, n1, Vector(20, 0, 0));
+
+    Simulator::ScheduleWithContext(n1->GetId(), Seconds(6.0), &MoveNode, n1, Vector(30, 0, 0));
+
+    Simulator::Stop(Seconds(10));
+    Simulator::Run();
+
+    Simulator::Destroy();
+    return 0;
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/helper/ns2-mobility-helper.cc ns-3.42/src/mobility/helper/ns2-mobility-helper.cc
--- ns-3.41/src/mobility/helper/ns2-mobility-helper.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/helper/ns2-mobility-helper.cc	2024-05-29 15:29:47.136073600 -0700
@@ -620,7 +620,8 @@
     {
         return false;
     }
-    else if (IsNumber(str))
+
+    if (IsNumber(str))
     {
         std::istringstream s(str);
         s >> ret;
@@ -681,8 +682,6 @@
         result = pr.ivals[0];
         break;
     case 7: // line like $ns_ at 4 "$node_(0) set X_ 28"
-        result = pr.ivals[3];
-        break;
     case 8: // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
         result = pr.ivals[3];
         break;
@@ -701,7 +700,6 @@
     case 4: // line like $node_(0) set X_ 11
         return pr.svals[0];
     case 7: // line like $ns_ at 4 "$node_(0) set X_ 28"
-        return pr.svals[3];
     case 8: // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
         return pr.svals[3];
     default:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/geocentric-constant-position-mobility-model.cc ns-3.42/src/mobility/model/geocentric-constant-position-mobility-model.cc
--- ns-3.41/src/mobility/model/geocentric-constant-position-mobility-model.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/mobility/model/geocentric-constant-position-mobility-model.cc	2024-05-29 15:29:47.136073600 -0700
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mattia Sandri <mattia.sandri@unipd.it>
+ */
+#include "geocentric-constant-position-mobility-model.h"
+
+#include <ns3/angles.h>
+
+#include <math.h>
+
+/**
+ *  \file
+ *  \ingroup mobility
+ *  Class GeocentricConstantPositionMobilityModel implementation.
+ */
+
+namespace ns3
+{
+
+NS_OBJECT_ENSURE_REGISTERED(GeocentricConstantPositionMobilityModel);
+
+TypeId
+GeocentricConstantPositionMobilityModel::GetTypeId()
+{
+    static TypeId tid =
+        TypeId("ns3::GeocentricConstantPositionMobilityModel")
+            .SetParent<MobilityModel>()
+            .SetGroupName("Mobility")
+            .AddConstructor<GeocentricConstantPositionMobilityModel>()
+            .AddAttribute(
+                "PositionLatLongAlt",
+                "The geographic position, in degrees (lat/lon) and meter (alt), in the order: "
+                "latitude, longitude and "
+                "altitude",
+                Vector3DValue({0, 0, 0}),
+                MakeVector3DAccessor(&GeocentricConstantPositionMobilityModel::m_position),
+                MakeVector3DChecker())
+            .AddAttribute("GeographicReferencePoint",
+                          "The point, in meters, taken as reference when converting from "
+                          "geographic to topographic.",
+                          Vector3DValue({0, 0, 0}),
+                          MakeVector3DAccessor(
+                              &GeocentricConstantPositionMobilityModel::m_geographicReferencePoint),
+                          MakeVector3DChecker());
+    return tid;
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::GetGeographicPosition() const
+{
+    return DoGetGeographicPosition();
+}
+
+void
+GeocentricConstantPositionMobilityModel::SetGeographicPosition(const Vector& latLonAlt)
+{
+    DoSetGeographicPosition(latLonAlt);
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::GetGeocentricPosition() const
+{
+    return DoGetGeocentricPosition();
+}
+
+void
+GeocentricConstantPositionMobilityModel::SetGeocentricPosition(const Vector& position)
+{
+    DoSetGeocentricPosition(position);
+}
+
+double
+GeocentricConstantPositionMobilityModel::GetElevationAngle(
+    Ptr<const GeocentricConstantPositionMobilityModel> other)
+{
+    return DoGetElevationAngle(other);
+}
+
+void
+GeocentricConstantPositionMobilityModel::SetCoordinateTranslationReferencePoint(
+    const Vector& position)
+{
+    DoSetCoordinateTranslationReferencePoint(position);
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::GetCoordinateTranslationReferencePoint() const
+{
+    return DoGetCoordinateTranslationReferencePoint();
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::GetPosition() const
+{
+    return DoGetPosition();
+}
+
+void
+GeocentricConstantPositionMobilityModel::SetPosition(const Vector& position)
+{
+    return DoSetPosition(position);
+}
+
+double
+GeocentricConstantPositionMobilityModel::GetDistanceFrom(
+    Ptr<const GeocentricConstantPositionMobilityModel> other) const
+{
+    return DoGetDistanceFrom(other);
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::DoGetPosition() const
+{
+    Vector topographicCoordinates =
+        GeographicPositions::GeographicToTopocentricCoordinates(m_position,
+                                                                m_geographicReferencePoint,
+                                                                GeographicPositions::SPHERE);
+    return topographicCoordinates;
+}
+
+void
+GeocentricConstantPositionMobilityModel::DoSetPosition(const Vector& position)
+{
+    Vector geographicCoordinates =
+        GeographicPositions::TopocentricToGeographicCoordinates(position,
+                                                                m_geographicReferencePoint,
+                                                                GeographicPositions::SPHERE);
+    m_position = geographicCoordinates;
+    NotifyCourseChange();
+}
+
+double
+GeocentricConstantPositionMobilityModel::DoGetDistanceFrom(
+    Ptr<const GeocentricConstantPositionMobilityModel> other) const
+{
+    Vector cartesianCoordA =
+        GeographicPositions::GeographicToCartesianCoordinates(m_position.x,
+                                                              m_position.y,
+                                                              m_position.z,
+                                                              GeographicPositions::SPHERE);
+    Vector cartesianCoordB = other->DoGetGeocentricPosition();
+
+    double distance = (cartesianCoordA - cartesianCoordB).GetLength();
+
+    return distance;
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::DoGetGeographicPosition() const
+{
+    return m_position;
+}
+
+void
+GeocentricConstantPositionMobilityModel::DoSetGeographicPosition(const Vector& latLonAlt)
+{
+    NS_ASSERT_MSG((latLonAlt.x >= -90) && (latLonAlt.x <= 90),
+                  "Latitude must be between -90 deg and +90 deg");
+    NS_ASSERT_MSG(latLonAlt.z >= 0, "Altitude must be higher or equal than 0 meters");
+
+    m_position = latLonAlt;
+    // Normalize longitude to [-180, 180]
+    m_position.y = WrapTo180(m_position.y);
+    NotifyCourseChange();
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::DoGetGeocentricPosition() const
+{
+    Vector geocentricCoordinates =
+        GeographicPositions::GeographicToCartesianCoordinates(m_position.x,
+                                                              m_position.y,
+                                                              m_position.z,
+                                                              GeographicPositions::SPHERE);
+    return geocentricCoordinates;
+}
+
+void
+GeocentricConstantPositionMobilityModel::DoSetGeocentricPosition(const Vector& position)
+{
+    Vector geographicCoordinates =
+        GeographicPositions::CartesianToGeographicCoordinates(position,
+                                                              GeographicPositions::SPHERE);
+    m_position = geographicCoordinates;
+    NotifyCourseChange();
+}
+
+double
+GeocentricConstantPositionMobilityModel::DoGetElevationAngle(
+    Ptr<const GeocentricConstantPositionMobilityModel> other)
+{
+    Vector me = this->DoGetGeocentricPosition();
+    Vector them = other->DoGetGeocentricPosition();
+
+    // a is assumed to be the terminal with the lowest altitude
+    Vector& a = (me.z < them.z ? me : them);
+    Vector& b = (me.z < them.z ? them : me);
+
+    Vector bMinusA = b - a;
+    double numerator = std::abs(a * bMinusA);
+    double denominator = a.GetLength() * bMinusA.GetLength();
+    double x = numerator / denominator;
+
+    // Enforce the appropriate domain range ([-1, 1]) for the argument of std::asin.
+    x = std::min(x, 1.0);
+    x = std::max(x, -1.0);
+
+    // asin returns radians, we convert to degrees
+    double elevAngle = abs((180.0 * M_1_PI) * asin(x));
+
+    return elevAngle;
+}
+
+void
+GeocentricConstantPositionMobilityModel::DoSetCoordinateTranslationReferencePoint(
+    const Vector& refPoint)
+{
+    m_geographicReferencePoint = refPoint;
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::DoGetCoordinateTranslationReferencePoint() const
+{
+    return m_geographicReferencePoint;
+}
+
+Vector
+GeocentricConstantPositionMobilityModel::DoGetVelocity() const
+{
+    return Vector(0.0, 0.0, 0.0);
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/geocentric-constant-position-mobility-model.h ns-3.42/src/mobility/model/geocentric-constant-position-mobility-model.h
--- ns-3.41/src/mobility/model/geocentric-constant-position-mobility-model.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/mobility/model/geocentric-constant-position-mobility-model.h	2024-05-29 15:29:47.136073600 -0700
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mattia Sandri <mattia.sandri@unipd.it>
+ */
+#ifndef GEOCENTRIC_CONSTANT_POSITION_MOBILITY_MODEL_H
+#define GEOCENTRIC_CONSTANT_POSITION_MOBILITY_MODEL_H
+
+#include "geographic-positions.h"
+#include "mobility-model.h"
+
+/**
+ * \file
+ * \ingroup mobility
+ * Class GeocentricConstantPositionMobilityModel declaration.
+ */
+
+namespace ns3
+{
+
+/**
+ * \brief Mobility model using geocentric euclidean coordinates, as defined in 38.811 chapter 6.3
+ */
+class GeocentricConstantPositionMobilityModel : public MobilityModel
+{
+  public:
+    /**
+     * Register this type with the TypeId system.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId();
+    /**
+     * Create a position located at coordinates (0,0,0)
+     */
+    GeocentricConstantPositionMobilityModel() = default;
+    ~GeocentricConstantPositionMobilityModel() override = default;
+
+    /**
+     * \brief Computes elevation angle between a ground terminal and a HAPS/Satellite.
+     * After calculating the plane perpendicular to a cartesian position vector,
+     * the elevation angle is calculated using
+     * https://www.w3schools.blog/angle-between-a-line-and-a-plane.
+     * The altitude of the position passed as a parameter must be higher than that of the reference
+     * point.
+     * \param other pointer to the HAPS/satellite mobility model
+     * \return the elevation angle
+     * in degrees
+     */
+    virtual double GetElevationAngle(Ptr<const GeocentricConstantPositionMobilityModel> other);
+
+    /**
+     * \brief Get the position using geographic (geodetic) coordinates
+     * \return Vector containing (latitude (degree), longitude (degree), altitude (meter))
+     */
+    virtual Vector GetGeographicPosition() const;
+
+    /**
+     * \brief Set the position using geographic coordinates
+     *
+     * Sets the position, using geographic coordinates and asserting
+     * that the provided parameter falls within the appropriate range.
+     *
+     * \param latLonAlt pointer to a Vector containing (latitude (degree), longitude (degree),
+     * altitude (meter)). The values are expected to be in the ranges [-90, 90], [-180, 180], [0,
+     * +inf[, respectively. These assumptions are enforced with an assert for the latitude and the
+     * altitude, while the longitude is normalized to the expected range.
+     */
+    virtual void SetGeographicPosition(const Vector& latLonAlt);
+
+    /**
+     * \brief Get the position using Geocentric Cartesian coordinates
+     * \return Vector containing (x, y, z) (meter) coordinates
+     */
+    virtual Vector GetGeocentricPosition() const;
+
+    /**
+     * \brief Set the position using Geocentric Cartesian coordinates
+     * \param position pointer to a Vector containing (x, y, z) (meter) coordinates
+     */
+    virtual void SetGeocentricPosition(const Vector& position);
+
+    /**
+     * \brief Set the reference point for coordinate conversion
+     * \param refPoint vector containing the geographic reference point (meter)
+     */
+    virtual void SetCoordinateTranslationReferencePoint(const Vector& refPoint);
+
+    /**
+     * \brief Get the reference point for coordinate conversion
+     * \return Vector containing geographic reference point (meter)
+     */
+    virtual Vector GetCoordinateTranslationReferencePoint() const;
+
+    /**
+     * \return the current position
+     */
+    virtual Vector GetPosition() const;
+
+    /**
+     * \param position the position to set.
+     */
+    virtual void SetPosition(const Vector& position);
+
+    /**
+     * \param other a reference to another mobility model
+     * \return the distance between the two objects. Unit is meters.
+     */
+    double GetDistanceFrom(Ptr<const GeocentricConstantPositionMobilityModel> other) const;
+
+  private:
+    /** \copydoc GetPosition() */
+    Vector DoGetPosition() const override;
+    /** \copydoc SetPosition() */
+    void DoSetPosition(const Vector& position) override;
+    /** \copydoc GetVelocity() */
+    Vector DoGetVelocity() const override;
+    /** \copydoc GetDistanceFrom() */
+    double DoGetDistanceFrom(Ptr<const GeocentricConstantPositionMobilityModel> other) const;
+    /** \copydoc GetGeographicPosition() */
+    virtual Vector DoGetGeographicPosition() const;
+    /** \copydoc SetGeographicPosition() */
+    virtual void DoSetGeographicPosition(const Vector& latLonAlt);
+    /** \copydoc GetGeocentricPosition() */
+    virtual Vector DoGetGeocentricPosition() const;
+    /** \copydoc SetGeocentricPosition() */
+    virtual void DoSetGeocentricPosition(const Vector& position);
+    /** \copydoc GetElevationAngle() */
+    virtual double DoGetElevationAngle(Ptr<const GeocentricConstantPositionMobilityModel> other);
+    /** \copydoc SetCoordinateTranslationReferencePoint() */
+    virtual void DoSetCoordinateTranslationReferencePoint(const Vector& refPoint);
+    /** \copydoc GetCoordinateTranslationReferencePoint() */
+    virtual Vector DoGetCoordinateTranslationReferencePoint() const;
+
+    /**
+     * the constant Geographic position,, in order: latitude (degree), longitude (degree), altitude
+     * (meter).
+     */
+    Vector m_position{0, 0, 0};
+
+    /**
+     * This is the point (meter) taken as a reference for converting
+     * from geographic to topographic (also referred to as planar Cartesian)
+     */
+    Vector m_geographicReferencePoint{0, 0, 0};
+};
+
+} // namespace ns3
+
+#endif /* GEOCENTRIC_CONSTANT_POSITION_MOBILITY_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/geographic-positions.cc ns-3.42/src/mobility/model/geographic-positions.cc
--- ns-3.41/src/mobility/model/geographic-positions.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/model/geographic-positions.cc	2024-05-29 15:29:47.136073600 -0700
@@ -19,18 +19,15 @@
 
 #include "geographic-positions.h"
 
+#include <ns3/angles.h>
 #include <ns3/log.h>
 
 #include <cmath>
 
 NS_LOG_COMPONENT_DEFINE("GeographicPositions");
 
-namespace ns3
+namespace
 {
-
-/// Earth's radius in meters if modeled as a perfect sphere
-static constexpr double EARTH_RADIUS = 6371e3;
-
 /**
  * GRS80 and WGS84 sources
  *
@@ -42,20 +39,14 @@
  * <https://web.archive.org/web/20200730231853/http://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf>.
  */
 
-/// Earth's semi-major axis in meters as defined by both GRS80 and WGS84
-static constexpr double EARTH_SEMIMAJOR_AXIS = 6378137;
-
-/// Earth's first eccentricity as defined by GRS80
-static constexpr double EARTH_GRS80_ECCENTRICITY = 0.0818191910428158;
-
-/// Earth's first eccentricity as defined by WGS84
-static constexpr double EARTH_WGS84_ECCENTRICITY = 0.0818191908426215;
-
-/// Conversion factor: degrees to radians
-static constexpr double DEG2RAD = M_PI / 180.0;
+/**
+ * \brief  Lambda function for computing the curvature
+ */
+auto curvature = [](double e, double ph) { return sqrt(1 - e * e * sin(ph) * sin(ph)); };
+} // namespace
 
-/// Conversion factor: radians to degrees
-static constexpr double RAD2DEG = 180.0 * M_1_PI;
+namespace ns3
+{
 
 Vector
 GeographicPositions::GeographicToCartesianCoordinates(double latitude,
@@ -64,31 +55,16 @@
                                                       EarthSpheroidType sphType)
 {
     NS_LOG_FUNCTION_NOARGS();
-    double latitudeRadians = DEG2RAD * latitude;
-    double longitudeRadians = DEG2RAD * longitude;
-    double a; // semi-major axis of earth
-    double e; // first eccentricity of earth
-    if (sphType == SPHERE)
-    {
-        a = EARTH_RADIUS;
-        e = 0;
-    }
-    else if (sphType == GRS80)
-    {
-        a = EARTH_SEMIMAJOR_AXIS;
-        e = EARTH_GRS80_ECCENTRICITY;
-    }
-    else // if sphType == WGS84
-    {
-        a = EARTH_SEMIMAJOR_AXIS;
-        e = EARTH_WGS84_ECCENTRICITY;
-    }
+    double latitudeRadians = DegreesToRadians(latitude);
+    double longitudeRadians = DegreesToRadians(longitude);
+
+    // Retrieve radius, first eccentricity and flattening according to the specified Earth's model
+    auto [a, e, f] = GetRadiusEccentFlat(sphType);
 
-    double Rn = a / (sqrt(1 - pow(e, 2) * pow(sin(latitudeRadians), 2))); // radius of
-                                                                          // curvature
+    double Rn = a / curvature(e, latitudeRadians); // radius of curvature
     double x = (Rn + altitude) * cos(latitudeRadians) * cos(longitudeRadians);
     double y = (Rn + altitude) * cos(latitudeRadians) * sin(longitudeRadians);
-    double z = ((1 - pow(e, 2)) * Rn + altitude) * sin(latitudeRadians);
+    double z = ((1 - e * e) * Rn + altitude) * sin(latitudeRadians);
     Vector cartesianCoordinates = Vector(x, y, z);
     return cartesianCoordinates;
 }
@@ -98,23 +74,8 @@
 {
     NS_LOG_FUNCTION(pos << sphType);
 
-    double a; // semi-major axis of earth
-    double e; // first eccentricity of earth
-    if (sphType == SPHERE)
-    {
-        a = EARTH_RADIUS;
-        e = 0;
-    }
-    else if (sphType == GRS80)
-    {
-        a = EARTH_SEMIMAJOR_AXIS;
-        e = EARTH_GRS80_ECCENTRICITY;
-    }
-    else // if sphType == WGS84
-    {
-        a = EARTH_SEMIMAJOR_AXIS;
-        e = EARTH_WGS84_ECCENTRICITY;
-    }
+    // Retrieve radius, first eccentricity and flattening according to the specified Earth's model
+    auto [a, e, f] = GetRadiusEccentFlat(sphType);
 
     Vector lla;
     Vector tmp;
@@ -134,10 +95,10 @@
         lla.x = atan2(pos.z, p * (1 - e2 * N / v));
     }
     // 1 m difference is approx 1 / 30 arc seconds = 9.26e-6 deg
-    while (fabs(lla.x - tmp.x) > 0.00000926 * DEG2RAD);
+    while (fabs(lla.x - tmp.x) > DegreesToRadians(0.00000926));
 
-    lla.x *= RAD2DEG;
-    lla.y *= RAD2DEG;
+    lla.x = RadiansToDegrees(lla.x);
+    lla.y = RadiansToDegrees(lla.y);
 
     // canonicalize (latitude) x in [-90, 90] and (longitude) y in [-180, 180)
     if (lla.x > 90.0)
@@ -165,6 +126,84 @@
     return lla;
 }
 
+Vector
+GeographicPositions::GeographicToTopocentricCoordinates(Vector pos,
+                                                        Vector refPoint,
+                                                        EarthSpheroidType sphType)
+{
+    NS_LOG_FUNCTION(pos << sphType);
+
+    double phi = DegreesToRadians(pos.x);
+    double lambda = DegreesToRadians(pos.y);
+    double h = pos.z;
+    double phi0 = DegreesToRadians(refPoint.x);
+    double lambda0 = DegreesToRadians(refPoint.y);
+    double h0 = refPoint.z;
+    // Retrieve radius, first eccentricity and flattening according to the specified Earth's model
+    auto [a, e, f] = GetRadiusEccentFlat(sphType);
+
+    // the radius of curvature in the prime vertical at latitude
+    double v = a / curvature(e, phi);
+    // the radius of curvature in the prime vertical at latitude
+    // of the reference point
+    double v0 = a / curvature(e, phi0);
+
+    double U = (v + h) * cos(phi) * sin(lambda - lambda0);
+    double V = (v + h) * (sin(phi) * cos(phi0) - cos(phi) * sin(phi0) * cos(lambda - lambda0)) +
+               e * e * (v0 * sin(phi0) - v * sin(phi)) * cos(phi0);
+    double W = (v + h) * (sin(phi) * sin(phi0) + cos(phi) * cos(phi0) * cos(lambda - lambda0)) +
+               e * e * (v0 * sin(phi0) - v * sin(phi)) * sin(phi0) - (v0 + h0);
+
+    Vector topocentricCoordinates = Vector(U, V, W);
+    return topocentricCoordinates;
+}
+
+Vector
+GeographicPositions::TopocentricToGeographicCoordinates(Vector pos,
+                                                        Vector refPoint,
+                                                        EarthSpheroidType sphType)
+{
+    NS_LOG_FUNCTION(pos << sphType);
+
+    double U = pos.x;
+    double V = pos.y;
+    double W = pos.z;
+    double phi0 = DegreesToRadians(refPoint.x);
+    double lambda0 = DegreesToRadians(refPoint.y);
+    double h0 = refPoint.z;
+    // Retrieve radius, first eccentricity and flattening according to the specified Earth's model
+    auto [a, e, f] = GetRadiusEccentFlat(sphType);
+
+    // the radius of curvature in the prime vertical at latitude
+    // of the reference point
+    double v0 = a / curvature(e, phi0);
+
+    double X0 = (v0 + h0) * cos(phi0) * cos(lambda0);
+    double Y0 = (v0 + h0) * cos(phi0) * sin(lambda0);
+    double Z0 = ((1 - e * e) * v0 + h0) * sin(phi0);
+
+    double X = X0 - U * sin(lambda0) - V * sin(phi0) * cos(lambda0) + W * cos(phi0) * cos(lambda0);
+    double Y = Y0 + U * cos(lambda0) - V * sin(phi0) * sin(lambda0) + W * cos(phi0) * sin(lambda0);
+    double Z = Z0 + V * cos(phi0) + W * sin(phi0);
+
+    double epsilon = e * e / (1 - e * e);
+    double b = a * (1 - f);
+    double p = sqrt(X * X + Y * Y);
+    double q = atan2((Z * a), (p * b));
+
+    double phi = atan2((Z + epsilon * b * pow(sin(q), 3)), (p - e * e * a * pow(cos(q), 3)));
+    double lambda = atan2(Y, X);
+
+    double v = a / curvature(e, phi);
+    double h = (p / cos(phi)) - v;
+
+    phi = RadiansToDegrees(phi);
+    lambda = RadiansToDegrees(lambda);
+
+    Vector geographicCoordinates = Vector(phi, lambda, h);
+    return geographicCoordinates;
+}
+
 std::list<Vector>
 GeographicPositions::RandCartesianPointsAroundGeographicPoint(double originLatitude,
                                                               double originLongitude,
@@ -194,27 +233,28 @@
         maxAltitude = 0;
     }
 
-    double originLatitudeRadians = originLatitude * DEG2RAD;
-    double originLongitudeRadians = originLongitude * DEG2RAD;
+    double originLatitudeRadians = DegreesToRadians(originLatitude);
+    double originLongitudeRadians = DegreesToRadians(originLongitude);
     double originColatitude = (M_PI_2)-originLatitudeRadians;
 
-    double a = maxDistFromOrigin / EARTH_RADIUS; // maximum alpha allowed
-                                                 // (arc length formula)
+    // maximum alpha allowed (arc length formula)
+    double a = maxDistFromOrigin / EARTH_SPHERE_RADIUS;
     if (a > M_PI)
     {
-        a = M_PI; // pi is largest alpha possible (polar angle from origin that
-                  // points can be generated within)
+        // pi is largest alpha possible (polar angle from origin that
+        // points can be generated within)
+        a = M_PI;
     }
 
     std::list<Vector> generatedPoints;
     for (int i = 0; i < numPoints; i++)
     {
         // random distance from North Pole (towards center of earth)
-        double d = uniRand->GetValue(0, EARTH_RADIUS - EARTH_RADIUS * cos(a));
+        double d = uniRand->GetValue(0, EARTH_SPHERE_RADIUS - EARTH_SPHERE_RADIUS * cos(a));
         // random angle in latitude slice (wrt Prime Meridian), radians
         double phi = uniRand->GetValue(0, M_PI * 2);
         // random angle from Center of Earth (wrt North Pole), radians
-        double alpha = acos((EARTH_RADIUS - d) / EARTH_RADIUS);
+        double alpha = acos((EARTH_SPHERE_RADIUS - d) / EARTH_SPHERE_RADIUS);
 
         // shift coordinate system from North Pole referred to origin point referred
         // reference: http://en.wikibooks.org/wiki/General_Astronomy/Coordinate_Systems
@@ -242,18 +282,48 @@
         // random altitude above earth's surface
         double randAltitude = uniRand->GetValue(0, maxAltitude);
 
-        Vector pointPosition =
-            GeographicPositions::GeographicToCartesianCoordinates(randPointLatitude * RAD2DEG,
-                                                                  randPointLongitude * RAD2DEG,
-                                                                  randAltitude,
-                                                                  SPHERE);
-        // convert coordinates
-        // from geographic to cartesian
+        // convert coordinates from geographic to cartesian
+        Vector pointPosition = GeographicPositions::GeographicToCartesianCoordinates(
+            RadiansToDegrees(randPointLatitude),
+            RadiansToDegrees(randPointLongitude),
+            randAltitude,
+            SPHERE);
 
-        generatedPoints.push_back(pointPosition); // add generated coordinate
-                                                  // points to list
+        // add generated coordinate points to list
+        generatedPoints.push_back(pointPosition);
     }
     return generatedPoints;
 }
 
+std::tuple<double, double, double>
+GeographicPositions::GetRadiusEccentFlat(EarthSpheroidType type)
+{
+    double a; // radius, in meters
+    double e; // first eccentricity
+    double f; // first flattening
+
+    switch (type)
+    {
+    case SPHERE:
+        a = EARTH_SPHERE_RADIUS;
+        e = EARTH_SPHERE_ECCENTRICITY;
+        f = EARTH_SPHERE_FLATTENING;
+        break;
+    case GRS80:
+        a = EARTH_SEMIMAJOR_AXIS;
+        e = EARTH_GRS80_ECCENTRICITY;
+        f = EARTH_GRS80_FLATTENING;
+        break;
+    case WGS84:
+        a = EARTH_SEMIMAJOR_AXIS;
+        e = EARTH_WGS84_ECCENTRICITY;
+        f = EARTH_WGS84_FLATTENING;
+        break;
+    default:
+        NS_FATAL_ERROR("The specified earth model is not supported!");
+    }
+
+    return std::make_tuple(a, e, f);
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/geographic-positions.h ns-3.42/src/mobility/model/geographic-positions.h
--- ns-3.41/src/mobility/model/geographic-positions.h	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/model/geographic-positions.h	2024-05-29 15:29:47.136073600 -0700
@@ -45,6 +45,37 @@
      * Mapping Agency, 1 Jan. 2000.
      * <https://web.archive.org/web/20200729203634/https://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf>.
      */
+
+    /// Earth's radius in meters if modeled as a perfect sphere
+    static constexpr double EARTH_SPHERE_RADIUS = 6371e3;
+
+    /// Earth's eccentricity if modeled as a perfect sphere
+    static constexpr double EARTH_SPHERE_ECCENTRICITY = 0;
+
+    /// Earth's flattening if modeled as a perfect sphere
+    static constexpr double EARTH_SPHERE_FLATTENING = 0;
+
+    /// <Earth's semi-major axis in meters as defined by both GRS80 and WGS84
+    /// https://en.wikipedia.org/wiki/World_Geodetic_System
+    static constexpr double EARTH_SEMIMAJOR_AXIS = 6378137;
+
+    /// Earth's first eccentricity as defined by GRS80
+    /// https://en.wikipedia.org/wiki/Geodetic_Reference_System_1980
+    static constexpr double EARTH_GRS80_ECCENTRICITY = 0.0818191910428158;
+
+    /// Earth's first flattening as defined by GRS80
+    /// https://en.wikipedia.org/wiki/Geodetic_Reference_System_1980
+    static constexpr double EARTH_GRS80_FLATTENING = 0.003352810681183637418;
+
+    /// Earth's first eccentricity as defined by
+    /// https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84
+    static constexpr double EARTH_WGS84_ECCENTRICITY = 0.0818191908426215;
+
+    /// Earth's first flattening as defined by WGS84
+    /// https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84
+    static constexpr double EARTH_WGS84_FLATTENING = 0.00335281;
+
+    /// The possible Earth spheroid models.  .
     enum EarthSpheroidType
     {
         SPHERE,
@@ -63,7 +94,7 @@
      * @param altitude height of the point (in meters) above earth's surface
      * @param sphType earth spheroid model to use for conversion
      *
-     * @return a vector containing the Cartesian coordinates (x, y, z referenced
+     * @return a vector representing the Cartesian coordinates (x, y, z referenced
      * in meters) of the point (origin (0, 0, 0) is center of earth)
      */
     static Vector GeographicToCartesianCoordinates(double latitude,
@@ -78,7 +109,7 @@
      * geographic coordinates. The residual delta is 1 m, which is approximately
      * 1 / 30 arc seconds or 9.26e-6 deg.
      *
-     * @param pos a vector containing the Cartesian coordinates (x, y, z referenced
+     * @param pos a vector representing the Cartesian coordinates (x, y, z referenced
      * in meters) of the point (origin (0, 0, 0) is center of earth)
      * @param sphType earth spheroid model to use for conversion
      *
@@ -92,6 +123,50 @@
     static Vector CartesianToGeographicCoordinates(Vector pos, EarthSpheroidType sphType);
 
     /**
+     * Conversion from geographic to topocentric coordinates.
+     *
+     * Conversion formulas taken from [1, Sec. 4.1.3 "Geographic/topocentric conversions"].
+     * [1] IOGP. Geomatics guidance note 7, part 2: coordinate conversions & transformations
+     * including formulas. IOGP Publication 373-7-2, International Association For Oil And Gas
+     * Producers, Sep. 2019
+     * https://www.iogp.org/bookstore/product/coordinate-conversions-and-transformation-including-formulas/
+     *
+     * @param pos a vector representing the Geographic coordinates (latitude, longitude, altitude)
+     * in degrees (lat/lon) and meters (altitude).
+     * @param refPoint a vector representing the reference point (latitude, longitude, altitude) in
+     * degrees (lat/lon) and meters (altitude). Default is (0,0,0)
+     * @param sphType earth spheroid model to use for conversion
+     *
+     * @return Vector position in meters and using planar Cartesian coordinates, i.e., ns-3's
+     * defaults
+     */
+    static Vector GeographicToTopocentricCoordinates(Vector pos,
+                                                     Vector refPoint,
+                                                     EarthSpheroidType sphType);
+
+    /**
+     * Conversion from topocentric to geographic.
+     *
+     * Conversion formulas taken from [1, Sec. 4.1.3 "Geographic/topocentric conversions"].
+     * [1] IOGP. Geomatics guidance note 7, part 2: coordinate conversions & transformations
+     * including formulas. IOGP Publication 373-7-2, International Association For Oil And Gas
+     * Producers, Sep. 2019
+     * https://www.iogp.org/bookstore/product/coordinate-conversions-and-transformation-including-formulas/
+     *
+     * @param pos a vector representing the topocentric coordinates (u, v, w) in meters, which
+     * represent the cartesian coordinates along the xEast, yNorth and zUp axes, respectively..
+     * @param refPoint a vector representing the reference point (latitude, longitude, altitude) in
+     * degrees (lat/lon) and meters (altitude). Default is (0,0,0)
+     * @param sphType earth spheroid model to use for conversion
+     *
+     * @return Vector position (latitude, longitude, altitude) in degrees (lat/lon) and meters
+     * (altitude) converted to geographic coordinates
+     */
+    static Vector TopocentricToGeographicCoordinates(Vector pos,
+                                                     Vector refPoint,
+                                                     EarthSpheroidType sphType);
+
+    /**
      * Generates uniformly distributed random points (in ECEF Cartesian
      * coordinates) within a given altitude above earth's surface centered around
      * a given origin point (on earth's surface, in geographic/geodetic coordinates)
@@ -123,6 +198,13 @@
         int numPoints,
         double maxDistFromOrigin,
         Ptr<UniformRandomVariable> uniRand);
+
+    /**
+     * @param type the type of model which is used to model the Earth
+     *
+     * @return the corresponding radius (in meters), first eccentricity and first flattening values
+     */
+    static std::tuple<double, double, double> GetRadiusEccentFlat(EarthSpheroidType type);
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/random-walk-2d-mobility-model.cc ns-3.42/src/mobility/model/random-walk-2d-mobility-model.cc
--- ns-3.41/src/mobility/model/random-walk-2d-mobility-model.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/model/random-walk-2d-mobility-model.cc	2024-05-29 15:29:47.136073600 -0700
@@ -94,45 +94,43 @@
     Vector position = m_helper.GetCurrentPosition();
 
     double speed = m_speed->GetValue();
-    double direction = 0;
-    if (!m_bounds.IsOnTheBorder(position))
+    double direction = m_direction->GetValue();
+    Vector velocity(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
+    if (m_bounds.IsOnTheBorder(position))
     {
-        direction = m_direction->GetValue();
-    }
-    else
-    {
-        Ptr<UniformRandomVariable> directionOverride = CreateObject<UniformRandomVariable>();
         switch (m_bounds.GetClosestSideOrCorner(position))
         {
         case Rectangle::RIGHTSIDE:
-            direction = directionOverride->GetValue(M_PI_2, M_PI + M_PI_2);
+            velocity.x = -1 * std::abs(velocity.x);
             break;
         case Rectangle::LEFTSIDE:
-            direction = directionOverride->GetValue(-M_PI_2, M_PI - M_PI_2);
+            velocity.x = std::abs(velocity.x);
             break;
         case Rectangle::TOPSIDE:
-            direction = directionOverride->GetValue(M_PI, 2 * M_PI);
+            velocity.y = -1 * std::abs(velocity.y);
             break;
         case Rectangle::BOTTOMSIDE:
-            direction = directionOverride->GetValue(0, M_PI);
+            velocity.y = std::abs(velocity.y);
             break;
         case Rectangle::TOPRIGHTCORNER:
-            direction = directionOverride->GetValue(M_PI, M_PI + M_PI_2);
+            velocity.x = -1 * std::abs(velocity.x);
+            velocity.y = -1 * std::abs(velocity.y);
             break;
         case Rectangle::TOPLEFTCORNER:
-            direction = directionOverride->GetValue(M_PI + M_PI_2, 2 * M_PI);
+            velocity.x = std::abs(velocity.x);
+            velocity.y = -1 * std::abs(velocity.y);
             break;
         case Rectangle::BOTTOMRIGHTCORNER:
-            direction = directionOverride->GetValue(0, M_PI_2);
-            direction += M_PI / 2;
+            velocity.x = -1 * std::abs(velocity.x);
+            velocity.y = std::abs(velocity.y);
             break;
         case Rectangle::BOTTOMLEFTCORNER:
-            direction = directionOverride->GetValue(M_PI_2, M_PI);
+            velocity.x = std::abs(velocity.x);
+            velocity.y = std::abs(velocity.y);
             break;
         }
     }
-    Vector vector(std::cos(direction) * speed, std::sin(direction) * speed, 0.0);
-    m_helper.SetVelocity(vector);
+    m_helper.SetVelocity(velocity);
     m_helper.Unpause();
 
     Time delayLeft;
@@ -151,10 +149,10 @@
 RandomWalk2dMobilityModel::DoWalk(Time delayLeft)
 {
     Vector position = m_helper.GetCurrentPosition();
-    Vector speed = m_helper.GetVelocity();
+    Vector velocity = m_helper.GetVelocity();
     Vector nextPosition = position;
-    nextPosition.x += speed.x * delayLeft.GetSeconds();
-    nextPosition.y += speed.y * delayLeft.GetSeconds();
+    nextPosition.x += velocity.x * delayLeft.GetSeconds();
+    nextPosition.y += velocity.y * delayLeft.GetSeconds();
     m_event.Cancel();
     if (m_bounds.IsInside(nextPosition))
     {
@@ -163,17 +161,17 @@
     }
     else
     {
-        nextPosition = m_bounds.CalculateIntersection(position, speed);
+        nextPosition = m_bounds.CalculateIntersection(position, velocity);
         double delaySeconds = std::numeric_limits<double>::max();
-        if (speed.x != 0)
+        if (velocity.x != 0)
         {
             delaySeconds =
-                std::min(delaySeconds, std::abs((nextPosition.x - position.x) / speed.x));
+                std::min(delaySeconds, std::abs((nextPosition.x - position.x) / velocity.x));
         }
-        else if (speed.y != 0)
+        else if (velocity.y != 0)
         {
             delaySeconds =
-                std::min(delaySeconds, std::abs((nextPosition.y - position.y) / speed.y));
+                std::min(delaySeconds, std::abs((nextPosition.y - position.y) / velocity.y));
         }
         else
         {
@@ -194,27 +192,26 @@
 {
     m_helper.UpdateWithBounds(m_bounds);
     Vector position = m_helper.GetCurrentPosition();
-    Vector speed = m_helper.GetVelocity();
+    Vector velocity = m_helper.GetVelocity();
     switch (m_bounds.GetClosestSideOrCorner(position))
     {
     case Rectangle::RIGHTSIDE:
     case Rectangle::LEFTSIDE:
-        speed.x = -speed.x;
+        velocity.x = -velocity.x;
         break;
     case Rectangle::TOPSIDE:
     case Rectangle::BOTTOMSIDE:
-        speed.y = -speed.y;
+        velocity.y = -velocity.y;
         break;
     case Rectangle::TOPRIGHTCORNER:
     case Rectangle::BOTTOMRIGHTCORNER:
     case Rectangle::TOPLEFTCORNER:
     case Rectangle::BOTTOMLEFTCORNER:
-        auto temp = speed.x;
-        speed.x = -speed.y;
-        speed.y = -temp;
+        velocity.x = -velocity.x;
+        velocity.y = -velocity.y;
         break;
     }
-    m_helper.SetVelocity(speed);
+    m_helper.SetVelocity(velocity);
     m_helper.Unpause();
     DoWalk(delayLeft);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/random-waypoint-mobility-model.cc ns-3.42/src/mobility/model/random-waypoint-mobility-model.cc
--- ns-3.41/src/mobility/model/random-waypoint-mobility-model.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/model/random-waypoint-mobility-model.cc	2024-05-29 15:29:47.136073600 -0700
@@ -66,15 +66,19 @@
     Vector m_current = m_helper.GetCurrentPosition();
     NS_ASSERT_MSG(m_position, "No position allocator added before using this model");
     Vector destination = m_position->GetNext();
+    Vector delta = destination - m_current;
+    double distance = delta.GetLength();
     double speed = m_speed->GetValue();
-    double dx = (destination.x - m_current.x);
-    double dy = (destination.y - m_current.y);
-    double dz = (destination.z - m_current.z);
-    double k = speed / std::sqrt(dx * dx + dy * dy + dz * dz);
 
-    m_helper.SetVelocity(Vector(k * dx, k * dy, k * dz));
+    NS_ASSERT_MSG(speed > 0, "Speed must be strictly positive.");
+
+    // Note: the following two lines are needed to prevent corner cases where
+    // the distance is null (and the Velocity is undefined).
+    double k = distance ? speed / distance : 0;
+    Time travelDelay = distance ? Seconds(distance / speed) : Time(0);
+
+    m_helper.SetVelocity(k * delta);
     m_helper.Unpause();
-    Time travelDelay = Seconds(CalculateDistance(destination, m_current) / speed);
     m_event.Cancel();
     m_event =
         Simulator::Schedule(travelDelay, &RandomWaypointMobilityModel::DoInitializePrivate, this);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/model/steady-state-random-waypoint-mobility-model.cc ns-3.42/src/mobility/model/steady-state-random-waypoint-mobility-model.cc
--- ns-3.41/src/mobility/model/steady-state-random-waypoint-mobility-model.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/model/steady-state-random-waypoint-mobility-model.cc	2024-05-29 15:29:47.136073600 -0700
@@ -183,7 +183,7 @@
         {
             pause = Seconds(u * expectedPauseTime);
         }
-        NS_ASSERT(!m_event.IsRunning());
+        NS_ASSERT(!m_event.IsPending());
         m_event =
             Simulator::Schedule(pause, &SteadyStateRandomWaypointMobilityModel::BeginWalk, this);
     }
@@ -209,7 +209,7 @@
         double u2 = m_u_r->GetValue(0, 1);
         m_helper.SetPosition(
             Vector(m_minX + u2 * x1 + (1 - u2) * x2, m_minY + u2 * y1 + (1 - u2) * y2, m_z));
-        NS_ASSERT(!m_event.IsRunning());
+        NS_ASSERT(!m_event.IsPending());
         m_event =
             Simulator::ScheduleNow(&SteadyStateRandomWaypointMobilityModel::SteadyStateBeginWalk,
                                    this,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/box-line-intersection-test.cc ns-3.42/src/mobility/test/box-line-intersection-test.cc
--- ns-3.41/src/mobility/test/box-line-intersection-test.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/test/box-line-intersection-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -31,7 +31,7 @@
  */
 
 BoxLineIntersectionTestSuite::BoxLineIntersectionTestSuite()
-    : TestSuite("box-line-intersection", UNIT)
+    : TestSuite("box-line-intersection", Type::UNIT)
 {
     // Box in the positive x-plane to check the intersection with.
     Box box = Box(890.0, 990.0, 840.0, 870.0, 0.0, 6.0);
@@ -42,28 +42,28 @@
     // Expected result: No intersection. The box is between the two position,
     // however, pos2 is above the height of the box.
     intersect = false;
-    AddTestCase(new BoxLineIntersectionTestCase(3, 6, box, intersect), TestCase::QUICK);
+    AddTestCase(new BoxLineIntersectionTestCase(3, 6, box, intersect), TestCase::Duration::QUICK);
 
     // Test #2 :
     // pos1 (index 1) is inside the box.
     // pos2 (index 2) is inside the box.
     // Expected result: Intersection.
     intersect = true;
-    AddTestCase(new BoxLineIntersectionTestCase(1, 2, box, intersect), TestCase::QUICK);
+    AddTestCase(new BoxLineIntersectionTestCase(1, 2, box, intersect), TestCase::Duration::QUICK);
 
     // Test #3 :
     // pos1 (index 3) is outside the box.
     // pos2 (index 1) is inside the box.
     // Expected result: Intersection.
     intersect = true;
-    AddTestCase(new BoxLineIntersectionTestCase(3, 1, box, intersect), TestCase::QUICK);
+    AddTestCase(new BoxLineIntersectionTestCase(3, 1, box, intersect), TestCase::Duration::QUICK);
 
     // Test #4:
     // pos1 (index 4) is outside the box.
     // pos2 (index 5) is outside the box.
     // Expected result: Intersection because box is in between the two positions.
     intersect = true;
-    AddTestCase(new BoxLineIntersectionTestCase(4, 5, box, intersect), TestCase::QUICK);
+    AddTestCase(new BoxLineIntersectionTestCase(4, 5, box, intersect), TestCase::Duration::QUICK);
 }
 
 static BoxLineIntersectionTestSuite boxLineIntersectionTestSuite; //!< boxLineIntersectionTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/gen-geocentric-topocentric-conversion-test-reference-points.sh ns-3.42/src/mobility/test/gen-geocentric-topocentric-conversion-test-reference-points.sh
--- ns-3.41/src/mobility/test/gen-geocentric-topocentric-conversion-test-reference-points.sh	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/mobility/test/gen-geocentric-topocentric-conversion-test-reference-points.sh	2024-05-29 15:29:47.136073600 -0700
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Generate test coordinates and reference conversion coordinates for the
+# GeocentricTopocentricConversionTest.
+# This script requires PROJ binaries, wchih can be installed by following
+# the official instructions:
+# https://proj.org/en/9.4/install.html#install
+
+# Configure printf to use dot-separated integer and decimal parts
+export LC_NUMERIC="en_US.UTF-8"
+# Coordinates to convert (long (degree), lat (degree), alt (meters)
+long_vec=(2.1295495 0.0 30.0 60.0 90.0 120.0 150.0 180.0)
+lat_vec=(53.809394 0.0 20.0 40.0 60.0 80.0)
+alt_vec=(73.0 500.0 1000.0)
+# Reference coordinates (long (degree), lat (degree), alt (meters).
+# In particular, the following ones are used as an example in
+# Sec. 4.1.3, "IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, part
+#  2 – September 2019".
+LONG_0=5
+LAT_0=55
+ALT_0=200
+# Reference elipsoids
+ellps_vec=(sphere GRS80 WGS84)
+# Convert geocentric -> topocentric coordinates
+# This conversion corresponds to EPSG Dataset coordinate operation
+# method code 9837, see "IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, part
+# 2 – September 2019".
+for ellps in ${ellps_vec[@]}; do
+  echo $ellps
+  proj_out=""
+  test_coord=""
+  for long in ${long_vec[@]}; do
+    for lat in ${lat_vec[@]}; do
+      for alt in ${alt_vec[@]}; do
+        # Coordinates conversion using PROJ
+        proj_coord=$(echo $long $lat $alt | cct -d 3 +proj=pipeline +ellps=$ellps +step +proj=cart +step +proj=topocentric +lon_0=$LONG_0 +lat_0=$LAT_0 +h_0=$ALT_0)
+        # Update test coordinates string
+        test_coord="$test_coord""$(printf "{%f, %f, %f}, " $lat $long $alt)"
+        # Update reference conversion coordinates string
+        proj_out="$proj_out""$(echo $proj_coord | awk '{print "{" $1 "," $2 "," $3 "},"}')"
+      done
+    done
+  done
+  # Output test coordinates and reference conversion coordinates as C++ vector of vectors
+  echo "test coordinates"
+  echo $test_coord
+  echo "converted points"
+  echo $proj_out
+done
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/geocentric-topocentric-conversion-test.cc ns-3.42/src/mobility/test/geocentric-topocentric-conversion-test.cc
--- ns-3.41/src/mobility/test/geocentric-topocentric-conversion-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/mobility/test/geocentric-topocentric-conversion-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2024 University of Padova
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Matteo Pagin <mattpagg@gmail.com>
+ */
+
+#include <ns3/angles.h>
+#include <ns3/geographic-positions.h>
+#include <ns3/log.h>
+#include <ns3/test.h>
+
+NS_LOG_COMPONENT_DEFINE("GeocentricTopocentricConversionTest");
+
+namespace
+{
+
+/// Test tolerance with respect to the expected values, in meters
+constexpr double TOLERANCE_M = 5;
+/// Test tolerance with respect to the expected values, in degrees
+constexpr double TOLERANCE_DEG = 5e-3;
+
+/**
+ * Reference point 1 for geocentric <--> topocentric conversion.
+ * In particular, this points is used for the example conversion of
+ * Sec. 4.1.3. of "IOGP Publication 373-7-2 – Geomatics Guidance
+ * Note number 7, part 2 – September 2019".
+ */
+const ns3::Vector REFP_1_COORD{55.0, 5.0, 200.0};
+
+/**
+ * Table of <longitude (deg), latitude (deg), altitude (m)> coordinates, obtained as the
+ * cartesian product of the longitude values
+ * (2.1295495 0.0 30.0 60.0 90.0 120.0 150.0 180.0), latitude values
+ * (53.80939444 0.0 20.0 40.0 60.0 80.0) and altitude values
+ * (73.0 500.0 1000.0).
+ * The first coordinate, i.e., (2.1295495, 53.80939444, 73.0) corresponds to that of the
+ * example provided in Sec. 4.1.3. of "IOGP Publication 373-7-2 – Geomatics Guidance
+ * Note number 7, part 2 – September 2019".
+ * This set of coordinates is, in principle, independent from the reference point.
+ */
+const std::vector<ns3::Vector> TEST_COORD = {
+    {53.809394, 2.129549, 73.000000},     {53.809394, 2.129549, 500.000000},
+    {53.809394, 2.129549, 1000.000000},   {0.000000, 2.129549, 73.000000},
+    {0.000000, 2.129549, 500.000000},     {0.000000, 2.129549, 1000.000000},
+    {20.000000, 2.129549, 73.000000},     {20.000000, 2.129549, 500.000000},
+    {20.000000, 2.129549, 1000.000000},   {40.000000, 2.129549, 73.000000},
+    {40.000000, 2.129549, 500.000000},    {40.000000, 2.129549, 1000.000000},
+    {60.000000, 2.129549, 73.000000},     {60.000000, 2.129549, 500.000000},
+    {60.000000, 2.129549, 1000.000000},   {80.000000, 2.129549, 73.000000},
+    {80.000000, 2.129549, 500.000000},    {80.000000, 2.129549, 1000.000000},
+    {53.809394, 0.000000, 73.000000},     {53.809394, 0.000000, 500.000000},
+    {53.809394, 0.000000, 1000.000000},   {0.000000, 0.000000, 73.000000},
+    {0.000000, 0.000000, 500.000000},     {0.000000, 0.000000, 1000.000000},
+    {20.000000, 0.000000, 73.000000},     {20.000000, 0.000000, 500.000000},
+    {20.000000, 0.000000, 1000.000000},   {40.000000, 0.000000, 73.000000},
+    {40.000000, 0.000000, 500.000000},    {40.000000, 0.000000, 1000.000000},
+    {60.000000, 0.000000, 73.000000},     {60.000000, 0.000000, 500.000000},
+    {60.000000, 0.000000, 1000.000000},   {80.000000, 0.000000, 73.000000},
+    {80.000000, 0.000000, 500.000000},    {80.000000, 0.000000, 1000.000000},
+    {53.809394, 30.000000, 73.000000},    {53.809394, 30.000000, 500.000000},
+    {53.809394, 30.000000, 1000.000000},  {0.000000, 30.000000, 73.000000},
+    {0.000000, 30.000000, 500.000000},    {0.000000, 30.000000, 1000.000000},
+    {20.000000, 30.000000, 73.000000},    {20.000000, 30.000000, 500.000000},
+    {20.000000, 30.000000, 1000.000000},  {40.000000, 30.000000, 73.000000},
+    {40.000000, 30.000000, 500.000000},   {40.000000, 30.000000, 1000.000000},
+    {60.000000, 30.000000, 73.000000},    {60.000000, 30.000000, 500.000000},
+    {60.000000, 30.000000, 1000.000000},  {80.000000, 30.000000, 73.000000},
+    {80.000000, 30.000000, 500.000000},   {80.000000, 30.000000, 1000.000000},
+    {53.809394, 60.000000, 73.000000},    {53.809394, 60.000000, 500.000000},
+    {53.809394, 60.000000, 1000.000000},  {0.000000, 60.000000, 73.000000},
+    {0.000000, 60.000000, 500.000000},    {0.000000, 60.000000, 1000.000000},
+    {20.000000, 60.000000, 73.000000},    {20.000000, 60.000000, 500.000000},
+    {20.000000, 60.000000, 1000.000000},  {40.000000, 60.000000, 73.000000},
+    {40.000000, 60.000000, 500.000000},   {40.000000, 60.000000, 1000.000000},
+    {60.000000, 60.000000, 73.000000},    {60.000000, 60.000000, 500.000000},
+    {60.000000, 60.000000, 1000.000000},  {80.000000, 60.000000, 73.000000},
+    {80.000000, 60.000000, 500.000000},   {80.000000, 60.000000, 1000.000000},
+    {53.809394, 90.000000, 73.000000},    {53.809394, 90.000000, 500.000000},
+    {53.809394, 90.000000, 1000.000000},  {0.000000, 90.000000, 73.000000},
+    {0.000000, 90.000000, 500.000000},    {0.000000, 90.000000, 1000.000000},
+    {20.000000, 90.000000, 73.000000},    {20.000000, 90.000000, 500.000000},
+    {20.000000, 90.000000, 1000.000000},  {40.000000, 90.000000, 73.000000},
+    {40.000000, 90.000000, 500.000000},   {40.000000, 90.000000, 1000.000000},
+    {60.000000, 90.000000, 73.000000},    {60.000000, 90.000000, 500.000000},
+    {60.000000, 90.000000, 1000.000000},  {80.000000, 90.000000, 73.000000},
+    {80.000000, 90.000000, 500.000000},   {80.000000, 90.000000, 1000.000000},
+    {53.809394, 120.000000, 73.000000},   {53.809394, 120.000000, 500.000000},
+    {53.809394, 120.000000, 1000.000000}, {0.000000, 120.000000, 73.000000},
+    {0.000000, 120.000000, 500.000000},   {0.000000, 120.000000, 1000.000000},
+    {20.000000, 120.000000, 73.000000},   {20.000000, 120.000000, 500.000000},
+    {20.000000, 120.000000, 1000.000000}, {40.000000, 120.000000, 73.000000},
+    {40.000000, 120.000000, 500.000000},  {40.000000, 120.000000, 1000.000000},
+    {60.000000, 120.000000, 73.000000},   {60.000000, 120.000000, 500.000000},
+    {60.000000, 120.000000, 1000.000000}, {80.000000, 120.000000, 73.000000},
+    {80.000000, 120.000000, 500.000000},  {80.000000, 120.000000, 1000.000000},
+    {53.809394, 150.000000, 73.000000},   {53.809394, 150.000000, 500.000000},
+    {53.809394, 150.000000, 1000.000000}, {0.000000, 150.000000, 73.000000},
+    {0.000000, 150.000000, 500.000000},   {0.000000, 150.000000, 1000.000000},
+    {20.000000, 150.000000, 73.000000},   {20.000000, 150.000000, 500.000000},
+    {20.000000, 150.000000, 1000.000000}, {40.000000, 150.000000, 73.000000},
+    {40.000000, 150.000000, 500.000000},  {40.000000, 150.000000, 1000.000000},
+    {60.000000, 150.000000, 73.000000},   {60.000000, 150.000000, 500.000000},
+    {60.000000, 150.000000, 1000.000000}, {80.000000, 150.000000, 73.000000},
+    {80.000000, 150.000000, 500.000000},  {80.000000, 150.000000, 1000.000000},
+    {53.809394, 180.000000, 73.000000},   {53.809394, 180.000000, 500.000000},
+    {53.809394, 180.000000, 1000.000000}, {0.000000, 180.000000, 73.000000},
+    {0.000000, 180.000000, 500.000000},   {0.000000, 180.000000, 1000.000000},
+    {20.000000, 180.000000, 73.000000},   {20.000000, 180.000000, 500.000000},
+    {20.000000, 180.000000, 1000.000000}, {40.000000, 180.000000, 73.000000},
+    {40.000000, 180.000000, 500.000000},  {40.000000, 180.000000, 1000.000000},
+    {60.000000, 180.000000, 73.000000},   {60.000000, 180.000000, 500.000000},
+    {60.000000, 180.000000, 1000.000000}, {80.000000, 180.000000, 73.000000},
+    {80.000000, 180.000000, 500.000000},  {80.000000, 180.000000, 1000.000000}};
+
+/**
+ * Table of expected geocentric coordinates <U, V, W> (meters) for spheroid type SPHERE
+ * and reference point 1
+ */
+const std::vector<ns3::Vector> SPHERE_REFP_1 = {
+    {-188390.250, -128514.834, -4209.801},     {-188402.876, -128523.447, -3783.074},
+    {-188417.661, -128533.533, -3283.395},     {-319049.537, -5212326.981, -2721486.356},
+    {-319070.921, -5212676.320, -2721241.747}, {-319095.960, -5213085.382, -2720955.318},
+    {-299808.496, -3648142.487, -1156630.460}, {-299828.590, -3648386.992, -1156280.970},
+    {-299852.118, -3648673.297, -1155871.733}, {-244406.125, -1643938.169, -220728.246},
+    {-244422.506, -1644048.348, -220316.032},  {-244441.687, -1644177.364, -219833.344},
+    {-159524.769, 558549.355, -26663.336},     {-159535.460, 558586.790, -26238.115},
+    {-159547.980, 558630.625, -25740.197},     {-55402.371, 2693667.583, -597842.821},
+    {-55406.084, 2693848.117, -597455.881},    {-55410.432, 2694059.516, -597002.790},
+    {-327875.291, -120654.830, -9713.435},     {-327897.266, -120662.917, -9287.077},
+    {-327922.997, -120672.386, -8787.830},     {-555275.338, -5199015.620, -2730807.072},
+    {-555312.553, -5199364.067, -2730563.087}, {-555356.131, -5199772.084, -2730277.390},
+    {-521788.138, -3635633.899, -1165389.067}, {-521823.109, -3635877.566, -1165040.165},
+    {-521864.059, -3636162.889, -1164631.614}, {-425365.587, -1633741.074, -227868.329},
+    {-425394.096, -1633850.571, -227456.592},  {-425427.478, -1633978.786, -226974.465},
+    {-277637.669, 565205.035, -31323.694},     {-277656.277, 565242.916, -30898.785},
+    {-277678.066, 565287.274, -30401.233},     {-96422.551, 2695979.077, -599461.346},
+    {-96429.013, 2696159.766, -599074.515},    {-96436.580, 2696371.345, -598621.550},
+    {1589867.531, 156341.271, -203668.193},    {1589974.086, 156351.749, -203254.835},
+    {1590098.859, 156364.019, -202770.808},    {2692530.529, -4729907.065, -3059280.418},
+    {2692710.987, -4730224.072, -3059058.447}, {2692922.296, -4730595.274, -3058798.529},
+    {2530151.069, -3194816.053, -1474053.046}, {2530320.644, -3195030.175, -1473724.831},
+    {2530519.210, -3195280.903, -1473340.505}, {2062598.050, -1274383.073, -479493.510},
+    {2062736.288, -1274468.485, -479098.638},  {2062898.161, -1274568.498, -478636.259},
+    {1346265.264, 799759.313, -195560.367},    {1346355.493, 799812.914, -195146.465},
+    {1346461.148, 799875.679, -194661.803},    {467553.020, 2777438.922, -656500.144},
+    {467584.356, 2777625.071, -656117.136},    {467621.049, 2777843.044, -655668.648},
+    {3081606.632, 1181688.408, -921623.987},   {3081813.166, 1181767.607, -921258.748},
+    {3082055.010, 1181860.345, -920831.067},   {5218875.015, -2993423.733, -4275179.137},
+    {5219224.793, -2993624.357, -4275038.659}, {5219634.369, -2993859.280, -4274874.164},
+    {4904138.340, -1563055.479, -2616624.101}, {4904467.024, -1563160.237, -2616372.463},
+    {4904851.900, -1563282.906, -2616077.805}, {3997890.204, 55840.334, -1410925.968},
+    {3998158.150, 55844.077, -1410593.522},    {3998471.903, 55848.459, -1410204.241},
+    {2609437.507, 1668000.979, -803509.727},   {2609612.396, 1668112.771, -803136.571},
+    {2609817.184, 1668243.676, -802699.620},   {906248.136, 3078976.088, -867638.741},
+    {906308.874, 3079182.447, -867269.883},    {906379.996, 3079424.084, -866837.965},
+    {3747631.724, 2680645.643, -1971205.143},  {3747882.897, 2680825.304, -1970910.248},
+    {3748177.010, 2681035.681, -1970564.938},  {6346826.155, -454854.928, -6052704.150},
+    {6347251.530, -454885.413, -6052682.805},  {6347749.628, -454921.110, -6052657.809},
+    {5964065.703, 822418.894, -4286951.239},   {5964465.425, 822474.014, -4286811.549},
+    {5964933.484, 822538.557, -4286647.978},   {4861950.908, 2000496.861, -2772589.126},
+    {4862276.764, 2000630.937, -2772347.942},  {4862658.329, 2000787.936, -2772065.524},
+    {3173413.078, 2937285.381, -1692272.233},  {3173625.765, 2937482.243, -1691958.644},
+    {3173874.814, 2937712.761, -1691591.443},  {1102114.796, 3519793.935, -1176302.720},
+    {1102188.661, 3520029.838, -1175954.550},  {1102275.155, 3520306.070, -1175546.856},
+    {3409481.922, 4251568.596, -3071177.236},  {3409710.432, 4251853.543, -3070956.063},
+    {3409978.007, 4252187.205, -3070697.079},  {5774150.353, 2205591.887, -7915569.065},
+    {5774537.346, 2205739.710, -7915672.572},  {5774990.500, 2205912.804, -7915793.774},
+    {5425926.478, 3322421.135, -6037471.653},  {5426290.133, 3322643.809, -6037449.286},
+    {5426715.958, 3322904.552, -6037423.096},  {4423255.791, 4038517.360, -4199626.443},
+    {4423552.246, 4038788.028, -4199480.900},  {4423899.382, 4039104.970, -4199310.476},
+    {2887075.176, 4267508.789, -2623704.691},  {2887268.673, 4267794.805, -2623453.527},
+    {2887495.250, 4268129.718, -2623159.425},  {1002670.686, 3981775.676, -1499785.818},
+    {1002737.887, 3982042.542, -1499459.328},  {1002816.576, 3982355.031, -1499077.021},
+    {2157764.193, 5473529.730, -3926803.634},  {2157908.810, 5473896.575, -3926639.806},
+    {2158078.151, 5474326.136, -3926447.971},  {3654295.626, 4275052.137, -9364620.733},
+    {3654540.543, 4275338.659, -9364821.357},  {3654827.332, 4275674.164, -9365056.280},
+    {3433914.634, 5267077.661, -7399134.812},  {3434144.781, 5267430.669, -7399203.706},
+    {3434414.274, 5267844.028, -7399284.378},  {2799352.858, 5623815.885, -5309664.420},
+    {2799540.475, 5624192.802, -5309593.275},  {2799760.168, 5624634.158, -5309509.966},
+    {1827147.813, 5302238.914, -3348230.524},  {1827270.272, 5302594.279, -3348027.920},
+    {1827413.666, 5303010.398, -3347790.678},  {634561.776, 4341133.678, -1751411.000},
+    {634604.306, 4341424.628, -1751101.374},   {634654.106, 4341765.319, -1750738.814},
+    {327875.291, 6019105.546, -4308819.933},   {327897.266, 6019508.957, -4308681.709},
+    {327922.997, 6019981.334, -4308519.854},   {555275.338, 5199015.620, -10011586.928},
+    {555312.553, 5199364.067, -10011830.913},  {555356.131, 5199772.084, -10012116.610},
+    {521788.138, 6135319.327, -8007084.172},   {521823.109, 6135730.527, -8007193.812},
+    {521864.059, 6136212.025, -8007322.196},   {425365.587, 6331612.976, -5805269.279},
+    {425394.096, 6332037.331, -5805231.350},   {425427.478, 6332534.235, -5805186.936},
+    {277637.669, 5764220.655, -3671713.622},   {277656.277, 5764606.983, -3671532.698},
+    {277678.066, 5765059.358, -3671320.843},   {96422.551, 4501578.253, -1863755.500},
+    {96429.013, 4501879.956, -1863453.404},    {96436.580, 4502233.239, -1863099.661}};
+
+/**
+ * Table of expected geocentric coordinates <U, V, W> (meters) for spheroid type GRS80
+ * and reference point 1
+ */
+const std::vector<ns3::Vector> GRS80_REFP_1 = {
+    {-189013.904, -128642.088, -4220.173},     {-189026.530, -128650.701, -3793.446},
+    {-189041.315, -128660.787, -3293.767},     {-319407.093, -5198061.834, -2710194.751},
+    {-319428.477, -5198411.173, -2709950.141}, {-319453.515, -5198820.235, -2709663.713},
+    {-300262.077, -3641934.701, -1153507.066}, {-300282.171, -3642179.206, -1153157.577},
+    {-300305.699, -3642465.511, -1152748.339}, {-245019.116, -1643718.675, -220614.182},
+    {-245035.496, -1643828.854, -220201.967},  {-245054.677, -1643957.870, -219719.280},
+    {-160105.977, 559428.176, -26712.769},     {-160116.668, 559465.611, -26287.548},
+    {-160129.188, 559509.446, -25789.630},     {-55645.391, 2701392.816, -599873.698},
+    {-55649.104, 2701573.351, -599486.758},    {-55653.452, 2701784.749, -599033.667},
+    {-328960.701, -120756.064, -9742.026},     {-328982.676, -120764.150, -9315.669},
+    {-329008.407, -120773.619, -8816.421},     {-555897.630, -5184735.555, -2719525.912},
+    {-555934.845, -5185084.002, -2719281.927}, {-555978.423, -5185492.019, -2718996.230},
+    {-522577.552, -3629407.189, -1162278.924}, {-522612.523, -3629650.855, -1161930.022},
+    {-522653.473, -3629936.179, -1161521.471}, {-426432.439, -1633496.005, -227772.172},
+    {-426460.948, -1633605.501, -227360.436},  {-426494.330, -1633733.717, -226878.309},
+    {-278649.206, 566108.106, -31390.106},     {-278667.814, 566145.987, -30965.197},
+    {-278689.603, 566190.344, -30467.646},     {-96845.504, 2703714.449, -601499.323},
+    {-96851.967, 2703895.138, -601112.492},    {-96859.534, 2704106.718, -600659.527},
+    {1595130.685, 157157.015, -204338.859},    {1595237.241, 157167.493, -203925.501},
+    {1595362.013, 157179.763, -203441.475},    {2695548.023, -4715101.275, -3048367.375},
+    {2695728.481, -4715418.281, -3048145.405}, {2695939.790, -4715789.483, -3047885.487},
+    {2533978.941, -3187922.428, -1471409.882}, {2534148.516, -3188136.550, -1471081.667},
+    {2534347.082, -3188387.278, -1470697.340}, {2067771.215, -1273236.705, -480028.450},
+    {2067909.453, -1273322.116, -479633.578},  {2068071.326, -1273422.129, -479171.199},
+    {1351170.209, 801516.952, -196225.155},    {1351260.438, 801570.553, -195811.253},
+    {1351366.092, 801633.318, -195326.590},    {469603.923, 2785531.615, -658788.320},
+    {469635.260, 2785717.764, -658405.311},    {469671.953, 2785935.737, -657956.823},
+    {3091808.092, 1185898.498, -924671.400},   {3092014.626, 1185977.696, -924306.160},
+    {3092256.470, 1186070.435, -923878.479},   {5224723.760, -2976671.881, -4265628.741},
+    {5225073.538, -2976872.506, -4265488.263}, {5225483.114, -2977107.429, -4265323.768},
+    {4911557.823, -1553693.159, -2615709.535}, {4911886.507, -1553797.918, -2615457.897},
+    {4912271.382, -1553920.586, -2615163.239}, {4007917.241, 60323.012, -1413797.017},
+    {4008185.186, 60326.755, -1413464.571},    {4008498.940, 60331.137, -1413075.290},
+    {2618944.657, 1672921.945, -806389.500},   {2619119.546, 1673033.737, -806016.344},
+    {2619324.334, 1673164.641, -805579.393},   {910223.359, 3088391.463, -870853.068},
+    {910284.098, 3088597.821, -870484.210},    {910355.220, 3088839.459, -870052.292},
+    {3760038.018, 2689817.934, -1977727.126},  {3760289.190, 2689997.596, -1977432.231},
+    {3760583.303, 2690207.972, -1977086.921},  {6353938.985, -435258.126, -6045145.811},
+    {6354364.360, -435288.611, -6045124.465},  {6354862.458, -435324.308, -6045099.469},
+    {5973088.753, 835390.203, -4288563.715},   {5973488.475, 835445.323, -4288424.025},
+    {5973956.533, 835509.867, -4288260.454},   {4874145.079, 2009856.896, -2778875.338},
+    {4874470.935, 2009990.973, -2778634.153},  {4874852.500, 2010147.972, -2778351.735},
+    {3184975.000, 2946830.821, -1698390.098},  {3185187.687, 2947027.683, -1698076.509},
+    {3185436.736, 2947258.201, -1697709.308},  {1106949.181, 3531142.941, -1180870.991},
+    {1107023.047, 3531378.844, -1180522.820},  {1107109.540, 3531655.076, -1180115.126},
+    {3420768.793, 4265941.326, -3081340.607},  {3420997.302, 4266226.274, -3081119.434},
+    {3421264.877, 4266559.936, -3080860.449},  {5780621.390, 2228170.228, -7910098.421},
+    {5781008.384, 2228318.050, -7910201.928},  {5781461.538, 2228491.145, -7910323.130},
+    {5434135.375, 3339174.703, -6041732.496},  {5434499.030, 3339397.377, -6041710.129},
+    {5434924.855, 3339658.120, -6041683.938},  {4434349.680, 4052988.918, -4209491.781},
+    {4434646.134, 4053259.586, -4209346.239},  {4434993.270, 4053576.528, -4209175.814},
+    {2897593.863, 4281900.727, -2633216.110},  {2897787.360, 4282186.743, -2632964.947},
+    {2898013.937, 4282521.656, -2632670.844},  {1007068.864, 3995151.148, -1505773.035},
+    {1007136.064, 3995418.013, -1505446.544},  {1007214.754, 3995730.502, -1505064.237},
+    {2164907.333, 5491947.684, -3939799.500},  {2165051.950, 5492314.529, -3939635.673},
+    {2165221.290, 5492744.090, -3939443.837},  {3658390.962, 4299949.703, -9360774.028},
+    {3658635.879, 4300236.225, -9360974.652},  {3658922.667, 4300571.730, -9361209.575},
+    {3439109.812, 5286773.305, -7405455.718},  {3439339.959, 5287126.313, -7405524.612},
+    {3439609.452, 5287539.672, -7405605.284},  {2806373.864, 5642263.501, -5322313.825},
+    {2806561.482, 5642640.419, -5322242.679},  {2806781.174, 5643081.775, -5322159.370},
+    {1833804.791, 5320400.758, -3360381.660},  {1833927.250, 5320756.123, -3360179.056},
+    {1834070.644, 5321172.242, -3359941.814},  {637345.258, 4356085.459, -1758501.961},
+    {637387.787, 4356376.410, -1758192.335},   {637437.587, 4356717.101, -1757829.775},
+    {328960.701, 6039329.594, -4323080.440},   {328982.676, 6039733.004, -4322942.215},
+    {329008.407, 6040205.382, -4322780.361},   {555897.630, 5224948.663, -10008465.272},
+    {555934.845, 5225297.110, -10008709.257},  {555978.423, 5225705.128, -10008994.954},
+    {522577.552, 6156328.536, -8014324.846},   {522612.523, 6156739.736, -8014434.486},
+    {522653.473, 6157221.234, -8014562.870},   {426432.439, 6351835.806, -5819161.701},
+    {426460.948, 6352260.161, -5819123.772},   {426494.330, 6352757.065, -5819079.358},
+    {278649.206, 5784065.670, -3685043.327},   {278667.814, 5784451.998, -3684862.403},
+    {278689.603, 5784904.373, -3684650.548},   {96845.504, 4517233.818, -1871339.256},
+    {96851.967, 4517535.522, -1871037.160},    {96859.534, 4517888.805, -1870683.417}};
+
+/**
+ * Table of expected geocentric coordinates <U, V, W> (meters) for spheroid type WGS84
+ * and reference point 1
+ */
+const std::vector<ns3::Vector> WGS_84_REFP_1 = {
+    {-189013.904, -128642.088, -4220.173},     {-189026.530, -128650.701, -3793.446},
+    {-189041.315, -128660.787, -3293.767},     {-319407.093, -5198061.834, -2710194.751},
+    {-319428.477, -5198411.173, -2709950.141}, {-319453.515, -5198820.235, -2709663.713},
+    {-300262.077, -3641934.701, -1153507.066}, {-300282.171, -3642179.206, -1153157.577},
+    {-300305.699, -3642465.511, -1152748.339}, {-245019.116, -1643718.675, -220614.182},
+    {-245035.496, -1643828.854, -220201.967},  {-245054.677, -1643957.870, -219719.280},
+    {-160105.977, 559428.176, -26712.769},     {-160116.668, 559465.611, -26287.548},
+    {-160129.188, 559509.446, -25789.630},     {-55645.391, 2701392.816, -599873.698},
+    {-55649.104, 2701573.351, -599486.758},    {-55653.452, 2701784.749, -599033.667},
+    {-328960.701, -120756.064, -9742.026},     {-328982.676, -120764.150, -9315.669},
+    {-329008.407, -120773.619, -8816.421},     {-555897.630, -5184735.555, -2719525.912},
+    {-555934.845, -5185084.002, -2719281.927}, {-555978.423, -5185492.019, -2718996.230},
+    {-522577.552, -3629407.189, -1162278.924}, {-522612.523, -3629650.855, -1161930.022},
+    {-522653.473, -3629936.179, -1161521.471}, {-426432.439, -1633496.005, -227772.172},
+    {-426460.948, -1633605.501, -227360.436},  {-426494.330, -1633733.717, -226878.309},
+    {-278649.206, 566108.106, -31390.106},     {-278667.814, 566145.987, -30965.197},
+    {-278689.603, 566190.344, -30467.646},     {-96845.504, 2703714.449, -601499.323},
+    {-96851.967, 2703895.138, -601112.492},    {-96859.534, 2704106.718, -600659.527},
+    {1595130.685, 157157.015, -204338.859},    {1595237.241, 157167.493, -203925.501},
+    {1595362.013, 157179.763, -203441.475},    {2695548.023, -4715101.275, -3048367.375},
+    {2695728.481, -4715418.282, -3048145.405}, {2695939.790, -4715789.483, -3047885.487},
+    {2533978.941, -3187922.428, -1471409.882}, {2534148.516, -3188136.550, -1471081.667},
+    {2534347.082, -3188387.278, -1470697.340}, {2067771.214, -1273236.705, -480028.450},
+    {2067909.453, -1273322.116, -479633.578},  {2068071.326, -1273422.129, -479171.199},
+    {1351170.209, 801516.952, -196225.155},    {1351260.438, 801570.553, -195811.253},
+    {1351366.092, 801633.318, -195326.590},    {469603.923, 2785531.615, -658788.320},
+    {469635.260, 2785717.764, -658405.311},    {469671.953, 2785935.737, -657956.823},
+    {3091808.092, 1185898.498, -924671.400},   {3092014.626, 1185977.696, -924306.160},
+    {3092256.470, 1186070.435, -923878.479},   {5224723.760, -2976671.881, -4265628.741},
+    {5225073.538, -2976872.506, -4265488.263}, {5225483.114, -2977107.429, -4265323.768},
+    {4911557.823, -1553693.160, -2615709.535}, {4911886.507, -1553797.918, -2615457.897},
+    {4912271.382, -1553920.586, -2615163.239}, {4007917.241, 60323.012, -1413797.016},
+    {4008185.186, 60326.755, -1413464.571},    {4008498.940, 60331.137, -1413075.290},
+    {2618944.657, 1672921.945, -806389.500},   {2619119.546, 1673033.737, -806016.344},
+    {2619324.334, 1673164.641, -805579.393},   {910223.359, 3088391.463, -870853.068},
+    {910284.098, 3088597.821, -870484.210},    {910355.220, 3088839.459, -870052.292},
+    {3760038.017, 2689817.934, -1977727.126},  {3760289.190, 2689997.596, -1977432.231},
+    {3760583.303, 2690207.972, -1977086.921},  {6353938.985, -435258.126, -6045145.811},
+    {6354364.360, -435288.611, -6045124.465},  {6354862.458, -435324.308, -6045099.470},
+    {5973088.753, 835390.203, -4288563.715},   {5973488.475, 835445.323, -4288424.025},
+    {5973956.533, 835509.867, -4288260.454},   {4874145.079, 2009856.896, -2778875.338},
+    {4874470.935, 2009990.973, -2778634.153},  {4874852.500, 2010147.972, -2778351.735},
+    {3184975.000, 2946830.821, -1698390.098},  {3185187.687, 2947027.683, -1698076.509},
+    {3185436.736, 2947258.201, -1697709.308},  {1106949.181, 3531142.941, -1180870.990},
+    {1107023.047, 3531378.843, -1180522.820},  {1107109.540, 3531655.076, -1180115.126},
+    {3420768.793, 4265941.326, -3081340.607},  {3420997.302, 4266226.274, -3081119.434},
+    {3421264.877, 4266559.936, -3080860.449},  {5780621.390, 2228170.228, -7910098.421},
+    {5781008.384, 2228318.050, -7910201.928},  {5781461.538, 2228491.145, -7910323.130},
+    {5434135.375, 3339174.703, -6041732.496},  {5434499.030, 3339397.377, -6041710.129},
+    {5434924.855, 3339658.120, -6041683.938},  {4434349.679, 4052988.918, -4209491.781},
+    {4434646.134, 4053259.586, -4209346.239},  {4434993.270, 4053576.528, -4209175.814},
+    {2897593.863, 4281900.727, -2633216.110},  {2897787.360, 4282186.743, -2632964.947},
+    {2898013.937, 4282521.656, -2632670.844},  {1007068.864, 3995151.148, -1505773.035},
+    {1007136.064, 3995418.013, -1505446.544},  {1007214.754, 3995730.502, -1505064.237},
+    {2164907.333, 5491947.684, -3939799.500},  {2165051.950, 5492314.529, -3939635.673},
+    {2165221.290, 5492744.090, -3939443.837},  {3658390.962, 4299949.703, -9360774.028},
+    {3658635.879, 4300236.225, -9360974.652},  {3658922.667, 4300571.730, -9361209.575},
+    {3439109.812, 5286773.305, -7405455.718},  {3439339.959, 5287126.313, -7405524.612},
+    {3439609.452, 5287539.672, -7405605.284},  {2806373.864, 5642263.501, -5322313.825},
+    {2806561.482, 5642640.419, -5322242.679},  {2806781.174, 5643081.775, -5322159.370},
+    {1833804.791, 5320400.758, -3360381.660},  {1833927.250, 5320756.123, -3360179.056},
+    {1834070.644, 5321172.242, -3359941.814},  {637345.258, 4356085.459, -1758501.961},
+    {637387.787, 4356376.410, -1758192.335},   {637437.587, 4356717.101, -1757829.775},
+    {328960.701, 6039329.593, -4323080.439},   {328982.676, 6039733.004, -4322942.215},
+    {329008.407, 6040205.382, -4322780.361},   {555897.630, 5224948.663, -10008465.272},
+    {555934.845, 5225297.110, -10008709.257},  {555978.423, 5225705.128, -10008994.954},
+    {522577.552, 6156328.536, -8014324.846},   {522612.523, 6156739.736, -8014434.486},
+    {522653.473, 6157221.234, -8014562.870},   {426432.439, 6351835.806, -5819161.701},
+    {426460.948, 6352260.161, -5819123.772},   {426494.330, 6352757.065, -5819079.358},
+    {278649.206, 5784065.670, -3685043.327},   {278667.814, 5784451.998, -3684862.403},
+    {278689.603, 5784904.373, -3684650.548},   {96845.504, 4517233.818, -1871339.256},
+    {96851.967, 4517535.522, -1871037.160},    {96859.534, 4517888.805, -1870683.417}};
+} // namespace
+
+using namespace ns3;
+
+/**
+ * \ingroup mobility-test
+ *
+ * \brief Geographic to/from Topocentric Test Case
+ *
+ * This test verifies the accuracy of the GeographicToTopocentricCoordinates and
+ * TopocentricToGeographicCoordinates methods in the GeographicPositions class,
+ * which convert geocentric (topocentric) coordinates to topocentric (geocentric)
+ * coordinates, respectively. In "IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, part
+ * 2 – September 2019", the two operations are also referred to as EPSG Dataset coordinate operation
+ * method code 9837.
+ *
+ * To this end, the values generated using the above methods are compared with the coordinates
+ * obtained using PROJ coordinate conversion utilities
+ * (https://proj.org/en/latest/operations/conversions/topocentric.html), for both sphere, GRS80 and
+ * WGS84 ellipsoid models. For instance, the coordinate (long, lat, alt) has been first
+ * converted to the topocentric coordinate system with reference point in (LONG_0, LAT_0, ALT_0)
+ * with the command echo $long $lat $alt | cct -d 3 +proj=pipeline +ellps=$ellps +step +proj=cart
+ * +step +proj=topocentric +lon_0=$LONG_0 +lat_0=$LAT_0 +h_0=$ALT_0. Then, the value obtained via
+ * PROJ is used to check both the forward (geo -> topo) and reverse (topo -> geo) conversion
+ */
+class GeoToAndFromTopocentricTestCase : public TestCase
+{
+  public:
+    /**
+     * @brief Constructor
+     *
+     * @param posToConvert a vector of positions to convert in geocentric coordinates, i.e.,
+     * represented as a vector (latitude (deg), longitude (deg), altitude (m))
+     * @param refPoint  the reference point, in geocentric coordinates, i.e., represented as a
+     * vector (latitude (deg), longitude (deg), altitude (m))
+     * @param expectedTopoCoord a vector of the corresponding expected topocentric coordinates,
+     * i.e., represented as (U (m), V (m), W (m)) with respect to the provided reference point
+     * @param sphereType spheroid type
+     */
+    GeoToAndFromTopocentricTestCase(const std::vector<Vector> posToConvert,
+                                    Vector refPoint,
+                                    const std::vector<Vector> expectedTopoCoord,
+                                    GeographicPositions::EarthSpheroidType sphereType);
+
+  private:
+    void DoRun() override;
+
+    /**
+     * @brief Test the forward and backward conversion for geocentric to topocentric coordinates
+     * for a given reference point
+     *
+     * @param posToConvert the position to convert, in geocentric coordinates, i.e., represented as
+     * a vector (latitude (deg), longitude (deg), altitude (m))
+     * @param refPoint  the reference point, in geocentric coordinates, i.e., represented as a
+     * vector (latitude (deg), longitude (deg), altitude (m))
+     * @param expectedTopoCoord the expected corresponding topocentric coordinates, i.e.,
+     * represented as (U (m), V (m), W (m)) with respect to the provided reference point
+     * @param sphereType spheroid type
+     */
+    void TestReferencePoint(Vector posToConvert,
+                            Vector refPoint,
+                            Vector expectedTopoCoord,
+                            GeographicPositions::EarthSpheroidType sphereType);
+
+    /**
+     * Manually check the test condition, i.e. equality between the expected
+     * and the obtained values, up to a given tolerance.
+     * @param actual the obtained test value
+     * @param limit the expected test value
+     * @param tol the tolerance error
+     * @param coord the string to display to describe the value
+     * @return whether the provided values satisfy the equality condition
+     */
+    bool CheckTestPass(double actual, double limit, double tol, std::string coord);
+
+    /// The position to convert, in geocentric coordinates, i.e.,
+    /// represented as a vector (latitude (deg), longitude (deg)///< altitude (m))
+    const std::vector<Vector> m_posToConvertGeoCoord;
+
+    /// The reference point, in geocentric coordinates, i.e., represented
+    /// as a vector (latitude (deg), longitude (deg), altitude (m))
+    Vector m_refPointGeoCoord;
+
+    /// The expected corresponding topocentric coordinates, i.e.,
+    /// represented as (U (m), V (m), W (m)) with respect to the
+    /// provided reference point
+    const std::vector<Vector> m_expectedTopoCoord;
+
+    GeographicPositions::EarthSpheroidType m_sphereType; ///< spheroid type
+};
+
+GeoToAndFromTopocentricTestCase::GeoToAndFromTopocentricTestCase(
+    const std::vector<Vector> posToConvert,
+    Vector refPoint,
+    const std::vector<Vector> expectedTopoCoord,
+    GeographicPositions::EarthSpheroidType sphereType)
+    : TestCase("Creating GeoToAndFromTopocentricTestCase"),
+      m_posToConvertGeoCoord(posToConvert),
+      m_refPointGeoCoord(refPoint),
+      m_expectedTopoCoord(expectedTopoCoord),
+      m_sphereType(sphereType)
+{
+}
+
+void
+GeoToAndFromTopocentricTestCase::TestReferencePoint(
+    Vector posToConvert,
+    Vector refPoint,
+    Vector expectedTopoCoord,
+    GeographicPositions::EarthSpheroidType sphereType)
+{
+    // Check forward conversion from geocentric to topocentric
+    Vector topoForwardConv =
+        GeographicPositions::GeographicToTopocentricCoordinates(posToConvert, refPoint, sphereType);
+
+    bool passGeoToTopo = (CheckTestPass(topoForwardConv.x, expectedTopoCoord.x, TOLERANCE_M, "U") &&
+                          CheckTestPass(topoForwardConv.y, expectedTopoCoord.y, TOLERANCE_M, "V") &&
+                          CheckTestPass(topoForwardConv.z, expectedTopoCoord.z, TOLERANCE_M, "W"));
+
+    // Check reverse conversion from topocentric to geocentric
+    Vector geoReverseConv = GeographicPositions::TopocentricToGeographicCoordinates(topoForwardConv,
+                                                                                    refPoint,
+                                                                                    sphereType);
+    geoReverseConv.x = WrapTo360(geoReverseConv.x);
+    geoReverseConv.y = WrapTo360(geoReverseConv.y);
+
+    bool passTopoToGeo = (CheckTestPass(geoReverseConv.x, posToConvert.x, TOLERANCE_DEG, "LAT") &&
+                          CheckTestPass(geoReverseConv.y, posToConvert.y, TOLERANCE_DEG, "LONG") &&
+                          CheckTestPass(geoReverseConv.z, posToConvert.z, TOLERANCE_M, "ALT"));
+
+    std::string geoToTopoMsg = passGeoToTopo ? "PASS" : "FAIL";
+    std::string topoToGeoMsg = passTopoToGeo ? "PASS" : "FAIL";
+
+    std::cout << geoToTopoMsg << " geocentric->topocentric for spheroid " << sphereType << " pos "
+              << posToConvert << " reference point " << refPoint << " expected coord "
+              << expectedTopoCoord << " actual " << topoForwardConv << std::endl;
+    std::cout << topoToGeoMsg << " topocentric->geocentric for spheroid " << sphereType << " pos "
+              << topoForwardConv << " reference point " << refPoint << " expected coord "
+              << posToConvert << " actual " << geoReverseConv << std::endl;
+}
+
+void
+GeoToAndFromTopocentricTestCase::DoRun()
+{
+    // Loop through test coordinates
+    for (unsigned int i = 0; i < m_posToConvertGeoCoord.size(); i++)
+    {
+        TestReferencePoint(m_posToConvertGeoCoord.at(i),
+                           m_refPointGeoCoord,
+                           m_expectedTopoCoord.at(i),
+                           m_sphereType);
+    }
+}
+
+bool
+GeoToAndFromTopocentricTestCase::CheckTestPass(double actual,
+                                               double limit,
+                                               double tol,
+                                               std::string coord)
+{
+    bool pass = ((actual) < (limit) + (tol) && (actual) > (limit) - (tol));
+
+    NS_TEST_EXPECT_MSG_EQ_TOL(actual,
+                              limit,
+                              tol,
+                              "Mismatch between expected " + coord + " and actual coordinates");
+
+    return pass;
+}
+
+/**
+ * \ingroup mobility-test
+ *
+ * \brief Geographic cartesian <--> Topocentric conversion test
+ */
+class GeoToAndFromTopocentricTestSuite : public TestSuite
+{
+  public:
+    GeoToAndFromTopocentricTestSuite();
+};
+
+GeoToAndFromTopocentricTestSuite::GeoToAndFromTopocentricTestSuite()
+    : TestSuite("geographic-topocentric-test", Type::UNIT)
+{
+    NS_LOG_INFO("creating GeoToAndFromTopocentricTestSuite");
+
+    // Test conversion for sphere ellipsoid model
+    AddTestCase(new GeoToAndFromTopocentricTestCase(TEST_COORD,    // pos
+                                                    REFP_1_COORD,  // ref point
+                                                    SPHERE_REFP_1, // expected topo coord
+                                                    GeographicPositions::SPHERE),
+                TestCase::Duration::QUICK);
+
+    // Test conversion for GRS80 ellipsoid model
+    AddTestCase(new GeoToAndFromTopocentricTestCase(TEST_COORD,   // pos
+                                                    REFP_1_COORD, // ref point
+                                                    GRS80_REFP_1, // expected topo coord
+                                                    GeographicPositions::GRS80),
+                TestCase::Duration::QUICK);
+
+    // Test conversion for WGS84 ellipsoid model
+    AddTestCase(new GeoToAndFromTopocentricTestCase(TEST_COORD,    // pos
+                                                    REFP_1_COORD,  // ref point
+                                                    WGS_84_REFP_1, // expected topo coord
+                                                    GeographicPositions::WGS84),
+                TestCase::Duration::QUICK);
+}
+
+/**
+ * \ingroup mobility-test
+ * Static variable for test initialization
+ */
+static GeoToAndFromTopocentricTestSuite g_GeoToAndFromTopocentricTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/geo-to-cartesian-test.cc ns-3.42/src/mobility/test/geo-to-cartesian-test.cc
--- ns-3.41/src/mobility/test/geo-to-cartesian-test.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/test/geo-to-cartesian-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -1800,7 +1800,7 @@
 };
 
 GeoToCartesianTestSuite::GeoToCartesianTestSuite()
-    : TestSuite("geo-to-cartesian", UNIT)
+    : TestSuite("geo-to-cartesian", Type::UNIT)
 {
     NS_LOG_INFO("creating GeoToCartesianTestSuite");
     int i = 0; // iteration number
@@ -1815,13 +1815,13 @@
                                                        altitude,
                                                        GeographicPositions::SPHERE,
                                                        i),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 AddTestCase(new CartesianToGeoTestCase(latitude,
                                                        longitude,
                                                        altitude,
                                                        GeographicPositions::SPHERE,
                                                        i),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 ++i;
             }
         }
@@ -1838,13 +1838,13 @@
                                                        altitude,
                                                        GeographicPositions::GRS80,
                                                        i),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 AddTestCase(new CartesianToGeoTestCase(latitude,
                                                        longitude,
                                                        altitude,
                                                        GeographicPositions::GRS80,
                                                        i),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 ++i;
             }
         }
@@ -1861,13 +1861,13 @@
                                                        altitude,
                                                        GeographicPositions::WGS84,
                                                        i),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 AddTestCase(new CartesianToGeoTestCase(latitude,
                                                        longitude,
                                                        altitude,
                                                        GeographicPositions::WGS84,
                                                        i),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 ++i;
             }
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/mobility-test-suite.cc ns-3.42/src/mobility/test/mobility-test-suite.cc
--- ns-3.41/src/mobility/test/mobility-test-suite.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/test/mobility-test-suite.cc	2024-05-29 15:29:47.136073600 -0700
@@ -484,12 +484,12 @@
 };
 
 MobilityTestSuite::MobilityTestSuite()
-    : TestSuite("mobility", UNIT)
+    : TestSuite("mobility", Type::UNIT)
 {
-    AddTestCase(new WaypointLazyNotifyFalse, TestCase::QUICK);
-    AddTestCase(new WaypointLazyNotifyTrue, TestCase::QUICK);
-    AddTestCase(new WaypointInitialPositionIsWaypoint, TestCase::QUICK);
-    AddTestCase(new WaypointMobilityModelViaHelper, TestCase::QUICK);
+    AddTestCase(new WaypointLazyNotifyFalse, TestCase::Duration::QUICK);
+    AddTestCase(new WaypointLazyNotifyTrue, TestCase::Duration::QUICK);
+    AddTestCase(new WaypointInitialPositionIsWaypoint, TestCase::Duration::QUICK);
+    AddTestCase(new WaypointMobilityModelViaHelper, TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/mobility-trace-test-suite.cc ns-3.42/src/mobility/test/mobility-trace-test-suite.cc
--- ns-3.41/src/mobility/test/mobility-trace-test-suite.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/test/mobility-trace-test-suite.cc	2024-05-29 15:29:47.136073600 -0700
@@ -124,9 +124,9 @@
 };
 
 MobilityTraceTestSuite::MobilityTraceTestSuite()
-    : TestSuite("mobility-trace", UNIT)
+    : TestSuite("mobility-trace", Type::UNIT)
 {
-    AddTestCase(new MobilityTraceTestCase, TestCase::QUICK);
+    AddTestCase(new MobilityTraceTestCase, TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/ns2-mobility-helper-test-suite.cc ns-3.42/src/mobility/test/ns2-mobility-helper-test-suite.cc
--- ns-3.41/src/mobility/test/ns2-mobility-helper-test-suite.cc	2024-02-09 14:44:08.365793500 -0800
+++ ns-3.42/src/mobility/test/ns2-mobility-helper-test-suite.cc	2024-05-29 15:29:47.136073600 -0700
@@ -328,7 +328,7 @@
 {
   public:
     Ns2MobilityHelperTestSuite()
-        : TestSuite("mobility-ns2-trace-helper", UNIT)
+        : TestSuite("mobility-ns2-trace-helper", Type::UNIT)
     {
         SetDataDir(NS_TEST_SOURCEDIR);
 
@@ -342,7 +342,7 @@
                     "$node_(0) set Y_ 2.0\n"
                     "$node_(0) set Z_ 3.0\n");
         t->AddReferencePoint("0", 0, Vector(1, 2, 3), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Check parsing comments, empty lines and no EOF at the end of file
         t = new Ns2MobilityHelperTest("comments", Seconds(1));
@@ -353,7 +353,7 @@
                     "$node_(0) set Z_ 3.0 # $node_(0) set Z_ 3.0\n"
                     "#$node_(0) set Z_ 100 #");
         t->AddReferencePoint("0", 0, Vector(1, 2, 3), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Simple setdest. Arguments are interpreted as x, y, speed by default
         t = new Ns2MobilityHelperTest("simple setdest", Seconds(10));
@@ -362,7 +362,7 @@
         t->AddReferencePoint("0", 0, Vector(0, 0, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 1, Vector(0, 0, 0), Vector(5, 0, 0));
         t->AddReferencePoint("0", 6, Vector(25, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Several set and setdest. Arguments are interpreted as x, y, speed by default
         t = new Ns2MobilityHelperTest("square setdest", Seconds(6));
@@ -382,7 +382,7 @@
         t->AddReferencePoint("0", 4, Vector(0, 5, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 4, Vector(0, 5, 0), Vector(0, -5, 0));
         t->AddReferencePoint("0", 5, Vector(0, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Copy of previous test case but with the initial positions at
         // the end of the trace rather than at the beginning.
@@ -405,7 +405,7 @@
         t->AddReferencePoint("0", 4, Vector(10, 15, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 4, Vector(10, 15, 0), Vector(0, -5, 0));
         t->AddReferencePoint("0", 5, Vector(10, 10, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Scheduled set position
         t = new Ns2MobilityHelperTest("scheduled set position", Seconds(2));
@@ -416,7 +416,7 @@
         t->AddReferencePoint("0", 1, Vector(10, 0, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 1, Vector(10, 0, 10), Vector(0, 0, 0));
         t->AddReferencePoint("0", 1, Vector(10, 10, 10), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Malformed lines
         t = new Ns2MobilityHelperTest("malformed lines", Seconds(2));
@@ -432,7 +432,7 @@
         t->AddReferencePoint("0", 0, Vector(1, 2, 3), Vector(0, 0, 0));
         t->AddReferencePoint("0", 1, Vector(1, 2, 3), Vector(1, 0, 0));
         t->AddReferencePoint("0", 2, Vector(2, 2, 3), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Non possible values
         t = new Ns2MobilityHelperTest("non possible values", Seconds(2));
@@ -453,7 +453,7 @@
         t->AddReferencePoint("0", 0, Vector(1, 2, 3), Vector(0, 0, 0));
         t->AddReferencePoint("0", 1, Vector(1, 2, 3), Vector(1, 0, 0));
         t->AddReferencePoint("0", 2, Vector(2, 2, 3), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // More than one node
         t = new Ns2MobilityHelperTest("few nodes, combinations of set and setdest", Seconds(10), 3);
@@ -481,7 +481,7 @@
         t->AddReferencePoint("2", 4, Vector(0, 5, 0), Vector(0, 0, 0));
         t->AddReferencePoint("2", 4, Vector(0, 5, 0), Vector(0, -5, 0));
         t->AddReferencePoint("2", 5, Vector(0, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Test for Speed == 0, that acts as stop the node.
         t = new Ns2MobilityHelperTest("setdest with speed cero", Seconds(10));
@@ -492,7 +492,7 @@
         t->AddReferencePoint("0", 1, Vector(0, 0, 0), Vector(5, 0, 0));
         t->AddReferencePoint("0", 6, Vector(25, 0, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 7, Vector(25, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Test negative positions
         t = new Ns2MobilityHelperTest("test negative positions", Seconds(10));
@@ -506,7 +506,7 @@
         t->AddReferencePoint("0", 2, Vector(0, 0, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 2, Vector(0, 0, 0), Vector(0, -1, 0));
         t->AddReferencePoint("0", 3, Vector(0, -1, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         // Square setdest with values in the form 1.0e+2
         t = new Ns2MobilityHelperTest("Foalt numbers in 1.0e+2 format", Seconds(6));
@@ -526,7 +526,7 @@
         t->AddReferencePoint("0", 4, Vector(0, 100, 0), Vector(0, 0, 0));
         t->AddReferencePoint("0", 4, Vector(0, 100, 0), Vector(0, -100, 0));
         t->AddReferencePoint("0", 5, Vector(0, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
         t = new Ns2MobilityHelperTest("Bug 1219 testcase", Seconds(16));
         t->SetTrace("$node_(0) set X_ 0.0\n"
                     "$node_(0) set Y_ 0.0\n"
@@ -537,13 +537,13 @@
         t->AddReferencePoint("0", 1, Vector(0, 0, 0), Vector(0, 1, 0));
         t->AddReferencePoint("0", 6, Vector(0, 5, 0), Vector(0, -1, 0));
         t->AddReferencePoint("0", 16, Vector(0, -10, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
         t = new Ns2MobilityHelperTest("Bug 1059 testcase", Seconds(16));
         t->SetTrace("$node_(0) set X_ 10.0\r\n"
                     "$node_(0) set Y_ 0.0\r\n");
         //                     id  t  position         velocity
         t->AddReferencePoint("0", 0, Vector(10, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
         t = new Ns2MobilityHelperTest("Bug 1301 testcase", Seconds(16));
         t->SetTrace("$node_(0) set X_ 10.0\n"
                     "$node_(0) set Y_ 0.0\n"
@@ -552,7 +552,7 @@
         // Moving to the current position must change nothing. No NaN
         // speed must be.
         t->AddReferencePoint("0", 0, Vector(10, 0, 0), Vector(0, 0, 0));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
 
         t = new Ns2MobilityHelperTest("Bug 1316 testcase", Seconds(1000));
         t->SetTrace("$node_(0) set X_ 350.00000000000000\n"
@@ -617,6 +617,6 @@
                              920.000,
                              Vector(300.000, 650.000, 0.000),
                              Vector(0.000, 0.000, 0.000));
-        AddTestCase(t, TestCase::QUICK);
+        AddTestCase(t, TestCase::Duration::QUICK);
     }
 } g_ns2TransmobilityHelperTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/rand-cart-around-geo-test.cc ns-3.42/src/mobility/test/rand-cart-around-geo-test.cc
--- ns-3.41/src/mobility/test/rand-cart-around-geo-test.cc	2024-02-09 14:44:08.369793400 -0800
+++ ns-3.42/src/mobility/test/rand-cart-around-geo-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -183,7 +183,7 @@
 };
 
 RandCartAroundGeoTestSuite::RandCartAroundGeoTestSuite()
-    : TestSuite("rand-cart-around-geo", UNIT)
+    : TestSuite("rand-cart-around-geo", Type::UNIT)
 {
     NS_LOG_INFO("creating RandCartAroundGeoTestSuite");
     Ptr<UniformRandomVariable> uniRand = CreateObject<UniformRandomVariable>();
@@ -201,7 +201,7 @@
                                                           50, // 50 points generated
                                                           maxDistFromOrigin,
                                                           uniRand),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
             }
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/rectangle-closest-border-test.cc ns-3.42/src/mobility/test/rectangle-closest-border-test.cc
--- ns-3.41/src/mobility/test/rectangle-closest-border-test.cc	2024-02-09 14:44:08.369793400 -0800
+++ ns-3.42/src/mobility/test/rectangle-closest-border-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -93,7 +93,7 @@
  */
 
 RectangleClosestBorderTestSuite::RectangleClosestBorderTestSuite()
-    : TestSuite("rectangle-closest-border", UNIT)
+    : TestSuite("rectangle-closest-border", Type::UNIT)
 {
     // Rectangle in the positive x-plane to check the intersection with.
     Rectangle rectangle = Rectangle(0.0, 10.0, 0.0, 10.0);
@@ -117,47 +117,47 @@
      */
     // Left side (1 and 15)
     AddTestCase(new RectangleClosestBorderTestCase(-5, 5, rectangle, Rectangle::LEFTSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(2, 5, rectangle, Rectangle::LEFTSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Right side (5 and 17)
     AddTestCase(new RectangleClosestBorderTestCase(17, 5, rectangle, Rectangle::RIGHTSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(7, 5, rectangle, Rectangle::RIGHTSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Bottom side (8 and 14)
     AddTestCase(new RectangleClosestBorderTestCase(5, -7, rectangle, Rectangle::BOTTOMSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(5, 1, rectangle, Rectangle::BOTTOMSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Top side (3 and 16)
     AddTestCase(new RectangleClosestBorderTestCase(5, 15, rectangle, Rectangle::TOPSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(5, 7, rectangle, Rectangle::TOPSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Left-Bottom corner (9 and 10)
     AddTestCase(new RectangleClosestBorderTestCase(-1, -1, rectangle, Rectangle::BOTTOMLEFTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(0, 0, rectangle, Rectangle::BOTTOMLEFTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Right-Bottom corner (7 and 13)
     AddTestCase(new RectangleClosestBorderTestCase(11, -1, rectangle, Rectangle::BOTTOMRIGHTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(9, 1, rectangle, Rectangle::BOTTOMRIGHTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Left-Top corner (2 and 11)
     AddTestCase(new RectangleClosestBorderTestCase(-1, 11, rectangle, Rectangle::TOPLEFTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(1, 9, rectangle, Rectangle::TOPLEFTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Right-Top corner (4 and 12)
     AddTestCase(new RectangleClosestBorderTestCase(11, 11, rectangle, Rectangle::TOPRIGHTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new RectangleClosestBorderTestCase(9, 9, rectangle, Rectangle::TOPRIGHTCORNER),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     // Central position (18)
     AddTestCase(new RectangleClosestBorderTestCase(5, 5, rectangle, Rectangle::TOPSIDE),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc ns-3.42/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc
--- ns-3.41/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc	2024-02-09 14:44:08.369793400 -0800
+++ ns-3.42/src/mobility/test/steady-state-random-waypoint-mobility-model-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -156,8 +156,8 @@
 struct SteadyStateRandomWaypointTestSuite : public TestSuite
 {
     SteadyStateRandomWaypointTestSuite()
-        : TestSuite("steady-state-rwp-mobility-model", UNIT)
+        : TestSuite("steady-state-rwp-mobility-model", Type::UNIT)
     {
-        AddTestCase(new SteadyStateRandomWaypointTest, TestCase::QUICK);
+        AddTestCase(new SteadyStateRandomWaypointTest, TestCase::Duration::QUICK);
     }
 } g_steadyStateRandomWaypointTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mobility/test/waypoint-mobility-model-test.cc ns-3.42/src/mobility/test/waypoint-mobility-model-test.cc
--- ns-3.41/src/mobility/test/waypoint-mobility-model-test.cc	2024-02-09 14:44:08.369793400 -0800
+++ ns-3.42/src/mobility/test/waypoint-mobility-model-test.cc	2024-05-29 15:29:47.136073600 -0700
@@ -259,10 +259,10 @@
 static struct WaypointMobilityModelTestSuite : public TestSuite
 {
     WaypointMobilityModelTestSuite()
-        : TestSuite("waypoint-mobility-model", UNIT)
+        : TestSuite("waypoint-mobility-model", Type::UNIT)
     {
-        AddTestCase(new WaypointMobilityModelNotifyTest(true), TestCase::QUICK);
-        AddTestCase(new WaypointMobilityModelNotifyTest(false), TestCase::QUICK);
-        AddTestCase(new WaypointMobilityModelAddWaypointTest(), TestCase::QUICK);
+        AddTestCase(new WaypointMobilityModelNotifyTest(true), TestCase::Duration::QUICK);
+        AddTestCase(new WaypointMobilityModelNotifyTest(false), TestCase::Duration::QUICK);
+        AddTestCase(new WaypointMobilityModelAddWaypointTest(), TestCase::Duration::QUICK);
     }
 } g_waypointMobilityModelTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/mpi/test/mpi-test-suite.cc ns-3.42/src/mpi/test/mpi-test-suite.cc
--- ns-3.41/src/mpi/test/mpi-test-suite.cc	2024-02-09 14:44:08.369793400 -0800
+++ ns-3.42/src/mpi/test/mpi-test-suite.cc	2024-05-29 15:29:47.140073500 -0700
@@ -116,9 +116,9 @@
                  const std::string dataDir,
                  const int ranks,
                  const std::string args = "",
-                 const TestDuration duration = QUICK,
+                 const Duration duration = Duration::QUICK,
                  const bool shouldNotErr = true)
-        : TestSuite(name, EXAMPLE)
+        : TestSuite(name, Type::EXAMPLE)
     {
         AddTestCase(new MpiTestCase(name, program, dataDir, ranks, args, shouldNotErr), duration);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/netanim/examples/wireless-animation.cc ns-3.42/src/netanim/examples/wireless-animation.cc
--- ns-3.41/src/netanim/examples/wireless-animation.cc	2024-02-09 14:44:08.397793500 -0800
+++ ns-3.42/src/netanim/examples/wireless-animation.cc	2024-05-29 15:29:47.144073700 -0700
@@ -30,6 +30,7 @@
 #include "ns3/yans-wifi-helper.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("WirelessAnimationExample");
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/netanim/model/animation-interface.cc ns-3.42/src/netanim/model/animation-interface.cc
--- ns-3.41/src/netanim/model/animation-interface.cc	2024-02-09 14:44:08.397793500 -0800
+++ ns-3.42/src/netanim/model/animation-interface.cc	2024-05-29 15:29:47.144073700 -0700
@@ -680,7 +680,7 @@
 
     NS_LOG_INFO("Remaining energy on one of sources on node " << nodeId << ": " << currentEnergy);
 
-    const Ptr<EnergySource> energySource = node->GetObject<EnergySource>();
+    const Ptr<energy::EnergySource> energySource = node->GetObject<energy::EnergySource>();
 
     NS_ASSERT(energySource);
     // Don't call GetEnergyFraction () because of recursion
@@ -1008,14 +1008,14 @@
 
     Ptr<NetDevice> ndev = GetNetDeviceFromContext(context);
     NS_ASSERT(ndev);
-    Ptr<LrWpanNetDevice> netDevice = DynamicCast<LrWpanNetDevice>(ndev);
+    Ptr<lrwpan::LrWpanNetDevice> netDevice = DynamicCast<lrwpan::LrWpanNetDevice>(ndev);
 
     Ptr<Node> n = ndev->GetNode();
     NS_ASSERT(n);
 
     UpdatePosition(n);
 
-    LrWpanMacHeader hdr;
+    lrwpan::LrWpanMacHeader hdr;
     if (!p->PeekHeader(hdr))
     {
         NS_LOG_WARN("LrWpanMacHeader not present");
@@ -2063,7 +2063,7 @@
     for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
     {
         Ptr<Node> n = *i;
-        if (NodeList::GetNode(n->GetId())->GetObject<EnergySource>())
+        if (NodeList::GetNode(n->GetId())->GetObject<energy::EnergySource>())
         {
             UpdateNodeCounter(m_remainingEnergyCounterId, n->GetId(), 1);
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/netanim/test/netanim-test.cc ns-3.42/src/netanim/test/netanim-test.cc
--- ns-3.41/src/netanim/test/netanim-test.cc	2024-02-09 14:44:08.397793500 -0800
+++ ns-3.42/src/netanim/test/netanim-test.cc	2024-05-29 15:29:47.144073700 -0700
@@ -32,6 +32,7 @@
 #include <iostream>
 
 using namespace ns3;
+using namespace ns3::energy;
 
 /**
  * \ingroup netanim
@@ -248,9 +249,9 @@
 {
   public:
     AnimationInterfaceTestSuite()
-        : TestSuite("animation-interface", UNIT)
+        : TestSuite("animation-interface", Type::UNIT)
     {
-        AddTestCase(new AnimationInterfaceTestCase(), TestCase::QUICK);
-        AddTestCase(new AnimationRemainingEnergyTestCase(), TestCase::QUICK);
+        AddTestCase(new AnimationInterfaceTestCase(), TestCase::Duration::QUICK);
+        AddTestCase(new AnimationRemainingEnergyTestCase(), TestCase::Duration::QUICK);
     }
 } g_animationInterfaceTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/CMakeLists.txt ns-3.42/src/network/CMakeLists.txt
--- ns-3.41/src/network/CMakeLists.txt	2024-02-09 14:44:08.397793500 -0800
+++ ns-3.42/src/network/CMakeLists.txt	2024-05-29 15:29:47.144073700 -0700
@@ -1,5 +1,6 @@
 set(source_files
     helper/application-container.cc
+    helper/application-helper.cc
     helper/delay-jitter-estimation.cc
     helper/net-device-container.cc
     helper/node-container.cc
@@ -73,6 +74,7 @@
 
 set(header_files
     helper/application-container.h
+    helper/application-helper.h
     helper/delay-jitter-estimation.h
     helper/net-device-container.h
     helper/node-container.h
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/helper/application-helper.cc ns-3.42/src/network/helper/application-helper.cc
--- ns-3.41/src/network/helper/application-helper.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/network/helper/application-helper.cc	2024-05-29 15:29:47.148073700 -0700
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2024 DERONNE SOFTWARE ENGINEERING
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
+ */
+
+#include "application-helper.h"
+
+#include <ns3/data-rate.h>
+#include <ns3/names.h>
+#include <ns3/string.h>
+
+namespace ns3
+{
+
+ApplicationHelper::ApplicationHelper(TypeId typeId)
+{
+    SetTypeId(typeId);
+}
+
+ApplicationHelper::ApplicationHelper(const std::string& typeId)
+{
+    SetTypeId(typeId);
+}
+
+void
+ApplicationHelper::SetTypeId(TypeId typeId)
+{
+    m_factory.SetTypeId(typeId);
+}
+
+void
+ApplicationHelper::SetTypeId(const std::string& typeId)
+{
+    m_factory.SetTypeId(typeId);
+}
+
+void
+ApplicationHelper::SetAttribute(const std::string& name, const AttributeValue& value)
+{
+    m_factory.Set(name, value);
+}
+
+ApplicationContainer
+ApplicationHelper::Install(Ptr<Node> node)
+{
+    return ApplicationContainer(DoInstall(node));
+}
+
+ApplicationContainer
+ApplicationHelper::Install(const std::string& nodeName)
+{
+    auto node = Names::Find<Node>(nodeName);
+    NS_ABORT_MSG_IF(!node, "Node " << nodeName << " does not exist");
+    return ApplicationContainer(DoInstall(node));
+}
+
+ApplicationContainer
+ApplicationHelper::Install(NodeContainer c)
+{
+    ApplicationContainer apps;
+    for (auto i = c.Begin(); i != c.End(); ++i)
+    {
+        apps.Add(DoInstall(*i));
+    }
+    return apps;
+}
+
+Ptr<Application>
+ApplicationHelper::DoInstall(Ptr<Node> node)
+{
+    NS_ABORT_MSG_IF(!node, "Node does not exist");
+    auto app = m_factory.Create<Application>();
+    node->AddApplication(app);
+    return app;
+}
+
+int64_t
+ApplicationHelper::AssignStreams(NodeContainer c, int64_t stream)
+{
+    NS_ABORT_MSG_IF(!m_factory.IsTypeIdSet(), "Type ID not set");
+    auto currentStream = stream;
+    for (auto i = c.Begin(); i != c.End(); ++i)
+    {
+        auto node = (*i);
+        for (uint32_t j = 0; j < node->GetNApplications(); ++j)
+        {
+            if (auto app = node->GetApplication(j);
+                app->GetInstanceTypeId() == m_factory.GetTypeId())
+            {
+                currentStream += app->AssignStreams(currentStream);
+            }
+        }
+    }
+    return (currentStream - stream);
+}
+
+int64_t
+ApplicationHelper::AssignStreamsToAllApps(NodeContainer c, int64_t stream)
+{
+    auto currentStream = stream;
+    for (auto i = c.Begin(); i != c.End(); ++i)
+    {
+        auto node = (*i);
+        for (uint32_t j = 0; j < node->GetNApplications(); ++j)
+        {
+            currentStream += node->GetApplication(j)->AssignStreams(currentStream);
+        }
+    }
+    return (currentStream - stream);
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/helper/application-helper.h ns-3.42/src/network/helper/application-helper.h
--- ns-3.41/src/network/helper/application-helper.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/network/helper/application-helper.h	2024-05-29 15:29:47.148073700 -0700
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2024 DERONNE SOFTWARE ENGINEERING
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
+ */
+
+#ifndef APPLICATIONS_HELPER_H
+#define APPLICATIONS_HELPER_H
+
+#include "application-container.h"
+#include "node-container.h"
+
+#include <ns3/address.h>
+#include <ns3/attribute.h>
+#include <ns3/object-factory.h>
+
+#include <string>
+
+namespace ns3
+{
+
+/**
+ * \brief A helper to make it easier to instantiate an application on a set of nodes.
+ */
+class ApplicationHelper
+{
+  public:
+    /**
+     * Create an application of a given type ID
+     *
+     * @param typeId the type ID.
+     */
+    explicit ApplicationHelper(TypeId typeId);
+
+    /**
+     * Create an application of a given type ID
+     *
+     * @param typeId the type ID expressed as a string.
+     */
+    explicit ApplicationHelper(const std::string& typeId);
+
+    /**
+     * Allow the helper to be repurposed for another application type
+     *
+     * @param typeId the type ID.
+     */
+    void SetTypeId(TypeId typeId);
+
+    /**
+     * Allow the helper to be repurposed for another application type
+     *
+     * @param typeId the type ID expressed as a string.
+     */
+    void SetTypeId(const std::string& typeId);
+
+    /**
+     * Helper function used to set the underlying application attributes.
+     *
+     * @param name the name of the application attribute to set
+     * @param value the value of the application attribute to set
+     */
+    void SetAttribute(const std::string& name, const AttributeValue& value);
+
+    /**
+     * Install an application on each node of the input container
+     * configured with all the attributes set with SetAttribute.
+     *
+     * @param c NodeContainer of the set of nodes on which an application
+     * will be installed.
+     * @return Container of Ptr to the applications installed.
+     */
+    ApplicationContainer Install(NodeContainer c);
+
+    /**
+     * Install an application on the node configured with all the
+     * attributes set with SetAttribute.
+     *
+     * @param node The node on which an application will be installed.
+     * @return Container of Ptr to the applications installed.
+     */
+    ApplicationContainer Install(Ptr<Node> node);
+
+    /**
+     * Install an application on the node configured with all the
+     * attributes set with SetAttribute.
+     *
+     * @param nodeName The node on which an application will be installed.
+     * @return Container of Ptr to the applications installed.
+     */
+    ApplicationContainer Install(const std::string& nodeName);
+
+    /**
+     * Assigns a unique (monotonically increasing) stream number to all applications that match the
+     * configured type of this application helper instance. Return the number of streams (possibly
+     * zero) that have been assigned. The Install() method should have previously been called by the
+     * user.
+     *
+     * @param stream first stream index to use
+     * @param c NodeContainer of the set of nodes for which the application should be modified to
+     * use a fixed stream
+     * @return the number of stream indices assigned by this helper
+     */
+    int64_t AssignStreams(NodeContainer c, int64_t stream);
+
+    /**
+     * Assign a fixed random variable stream number to the random variables used by all the
+     * applications. Return the number of streams (possibly zero) that have been assigned. The
+     * Install() method should have previously been called by the user.
+     *
+     * @param stream first stream index to use
+     * @param c NodeContainer of the set of nodes for which their applications should be modified to
+     * use a fixed stream
+     * @return the number of stream indices assigned by this helper
+     */
+    static int64_t AssignStreamsToAllApps(NodeContainer c, int64_t stream);
+
+  protected:
+    /**
+     * Install an application on the node configured with all the
+     * attributes set with SetAttribute.
+     *
+     * @param node The node on which an application will be installed.
+     * @return Ptr to the application installed.
+     */
+    virtual Ptr<Application> DoInstall(Ptr<Node> node);
+
+    ObjectFactory m_factory; //!< Object factory.
+};
+
+} // namespace ns3
+
+#endif /* APPLICATIONS_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/model/address.cc ns-3.42/src/network/model/address.cc
--- ns-3.41/src/network/model/address.cc	2024-02-09 14:44:08.401793700 -0800
+++ ns-3.42/src/network/model/address.cc	2024-05-29 15:29:47.148073700 -0700
@@ -245,6 +245,10 @@
 std::ostream&
 operator<<(std::ostream& os, const Address& address)
 {
+    if (address.m_len == 0)
+    {
+        return os;
+    }
     os.setf(std::ios::hex, std::ios::basefield);
     os.fill('0');
     os << std::setw(2) << (uint32_t)address.m_type << "-" << std::setw(2) << (uint32_t)address.m_len
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/model/application.cc ns-3.42/src/network/model/application.cc
--- ns-3.41/src/network/model/application.cc	2024-02-09 14:44:08.401793700 -0800
+++ ns-3.42/src/network/model/application.cc	2024-05-29 15:29:47.148073700 -0700
@@ -132,4 +132,11 @@
     NS_LOG_FUNCTION(this);
 }
 
+int64_t
+Application::AssignStreams(int64_t stream)
+{
+    NS_LOG_FUNCTION(this << stream);
+    return 0;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/model/application.h ns-3.42/src/network/model/application.h
--- ns-3.41/src/network/model/application.h	2024-02-09 14:44:08.401793700 -0800
+++ ns-3.42/src/network/model/application.h	2024-05-29 15:29:47.148073700 -0700
@@ -106,6 +106,15 @@
     void SetNode(Ptr<Node> node);
 
     /**
+     * \brief Assign a fixed random variable stream number to the random variables
+     * used by this Application object.
+     *
+     * \param stream first stream index to use
+     * \return the number of stream indices assigned by this Application object
+     */
+    virtual int64_t AssignStreams(int64_t stream);
+
+    /**
      * \brief Common callback signature for packet delay and address.
      *
      * \param delay The packet delay.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/model/node.cc ns-3.42/src/network/model/node.cc
--- ns-3.41/src/network/model/node.cc	2024-02-09 14:44:08.401793700 -0800
+++ ns-3.42/src/network/model/node.cc	2024-05-29 15:29:47.148073700 -0700
@@ -116,21 +116,18 @@
 uint32_t
 Node::GetId() const
 {
-    NS_LOG_FUNCTION(this);
     return m_id;
 }
 
 Time
 Node::GetLocalTime() const
 {
-    NS_LOG_FUNCTION(this);
     return Simulator::Now();
 }
 
 uint32_t
 Node::GetSystemId() const
 {
-    NS_LOG_FUNCTION(this);
     return m_sid;
 }
 
@@ -151,7 +148,6 @@
 Ptr<NetDevice>
 Node::GetDevice(uint32_t index) const
 {
-    NS_LOG_FUNCTION(this << index);
     NS_ASSERT_MSG(index < m_devices.size(),
                   "Device index " << index << " is out of range (only have " << m_devices.size()
                                   << " devices).");
@@ -161,7 +157,6 @@
 uint32_t
 Node::GetNDevices() const
 {
-    NS_LOG_FUNCTION(this);
     return m_devices.size();
 }
 
@@ -179,7 +174,6 @@
 Ptr<Application>
 Node::GetApplication(uint32_t index) const
 {
-    NS_LOG_FUNCTION(this << index);
     NS_ASSERT_MSG(index < m_applications.size(),
                   "Application index " << index << " is out of range (only have "
                                        << m_applications.size() << " applications).");
@@ -189,7 +183,6 @@
 uint32_t
 Node::GetNApplications() const
 {
-    NS_LOG_FUNCTION(this);
     return m_applications.size();
 }
 
@@ -284,7 +277,6 @@
 bool
 Node::ChecksumEnabled()
 {
-    NS_LOG_FUNCTION_NOARGS();
     BooleanValue val;
     g_checksumEnabled.GetValue(val);
     return val.Get();
@@ -333,9 +325,6 @@
                   "Received packet with erroneous context ; "
                       << "make sure the channels in use are correctly updating events context "
                       << "when transferring events from one node to another.");
-    NS_LOG_DEBUG("Node " << GetId() << " ReceiveFromDevice:  dev " << device->GetIfIndex()
-                         << " (type=" << device->GetInstanceTypeId().GetName() << ") Packet UID "
-                         << packet->GetUid());
     bool found = false;
 
     for (auto i = m_handlers.begin(); i != m_handlers.end(); i++)
@@ -352,6 +341,9 @@
             }
         }
     }
+    NS_LOG_DEBUG("Node " << GetId() << " ReceiveFromDevice:  dev " << device->GetIfIndex()
+                         << " (type=" << device->GetInstanceTypeId().GetName() << ") Packet UID "
+                         << packet->GetUid() << " handler found: " << found);
     return found;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/model/socket.h ns-3.42/src/network/model/socket.h
--- ns-3.41/src/network/model/socket.h	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/model/socket.h	2024-05-29 15:29:47.148073700 -0700
@@ -779,9 +779,11 @@
      * \brief Manually set IP Type of Service field
      *
      * This method corresponds to using setsockopt () IP_TOS of
-     * real network or BSD sockets. This option is for IPv4 only.
+     * real network or BSD sockets.
      * Setting the IP TOS also changes the socket priority as
      * stated in the man page.
+     * This option affects only IPv4 sockets, it has no effect
+     * on IPv6 sockets.
      *
      * \param ipTos The desired TOS value for IP headers
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/bit-serializer-test.cc ns-3.42/src/network/test/bit-serializer-test.cc
--- ns-3.41/src/network/test/bit-serializer-test.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/bit-serializer-test.cc	2024-05-29 15:29:47.148073700 -0700
@@ -153,10 +153,10 @@
 };
 
 BitSerializerTestSuite::BitSerializerTestSuite()
-    : TestSuite("bit-serializer", UNIT)
+    : TestSuite("bit-serializer", Type::UNIT)
 {
-    AddTestCase(new BitSerializerTest, TestCase::QUICK);
-    AddTestCase(new BitDeserializerTest, TestCase::QUICK);
+    AddTestCase(new BitSerializerTest, TestCase::Duration::QUICK);
+    AddTestCase(new BitDeserializerTest, TestCase::Duration::QUICK);
 }
 
 static BitSerializerTestSuite g_bitSerializerTest; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/buffer-test.cc ns-3.42/src/network/test/buffer-test.cc
--- ns-3.41/src/network/test/buffer-test.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/buffer-test.cc	2024-05-29 15:29:47.148073700 -0700
@@ -408,9 +408,9 @@
 };
 
 BufferTestSuite::BufferTestSuite()
-    : TestSuite("buffer", UNIT)
+    : TestSuite("buffer", Type::UNIT)
 {
-    AddTestCase(new BufferTest, TestCase::QUICK);
+    AddTestCase(new BufferTest, TestCase::Duration::QUICK);
 }
 
 static BufferTestSuite g_bufferTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/drop-tail-queue-test-suite.cc ns-3.42/src/network/test/drop-tail-queue-test-suite.cc
--- ns-3.41/src/network/test/drop-tail-queue-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/drop-tail-queue-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -97,9 +97,9 @@
 {
   public:
     DropTailQueueTestSuite()
-        : TestSuite("drop-tail-queue", UNIT)
+        : TestSuite("drop-tail-queue", Type::UNIT)
     {
-        AddTestCase(new DropTailQueueTestCase(), TestCase::QUICK);
+        AddTestCase(new DropTailQueueTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/error-model-test-suite.cc ns-3.42/src/network/test/error-model-test-suite.cc
--- ns-3.41/src/network/test/error-model-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/error-model-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -305,10 +305,10 @@
 };
 
 ErrorModelTestSuite::ErrorModelTestSuite()
-    : TestSuite("error-model", UNIT)
+    : TestSuite("error-model", Type::UNIT)
 {
-    AddTestCase(new ErrorModelSimple, TestCase::QUICK);
-    AddTestCase(new BurstErrorModelSimple, TestCase::QUICK);
+    AddTestCase(new ErrorModelSimple, TestCase::Duration::QUICK);
+    AddTestCase(new BurstErrorModelSimple, TestCase::Duration::QUICK);
 }
 
 // Do not forget to allocate an instance of this TestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/ipv6-address-test-suite.cc ns-3.42/src/network/test/ipv6-address-test-suite.cc
--- ns-3.41/src/network/test/ipv6-address-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/ipv6-address-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -109,9 +109,9 @@
 };
 
 Ipv6AddressTestSuite::Ipv6AddressTestSuite()
-    : TestSuite("ipv6-address", UNIT)
+    : TestSuite("ipv6-address", Type::UNIT)
 {
-    AddTestCase(new Ipv6AddressTestCase, TestCase::QUICK);
+    AddTestCase(new Ipv6AddressTestCase, TestCase::Duration::QUICK);
 }
 
 static Ipv6AddressTestSuite ipv6AddressTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/lollipop-counter-test.cc ns-3.42/src/network/test/lollipop-counter-test.cc
--- ns-3.41/src/network/test/lollipop-counter-test.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/lollipop-counter-test.cc	2024-05-29 15:29:47.148073700 -0700
@@ -150,19 +150,19 @@
  *
  * \brief Lollipop Counter TestSuite
  */
-class LolipopCounterTestSuite : public TestSuite
+class LollipopCounterTestSuite : public TestSuite
 {
   public:
-    LolipopCounterTestSuite();
+    LollipopCounterTestSuite();
 
   private:
 };
 
-LolipopCounterTestSuite::LolipopCounterTestSuite()
-    : TestSuite("lollipop-counter", UNIT)
+LollipopCounterTestSuite::LollipopCounterTestSuite()
+    : TestSuite("lollipop-counter", Type::UNIT)
 {
-    AddTestCase(new LollipopCounterTest(), TestCase::QUICK);
+    AddTestCase(new LollipopCounterTest(), TestCase::Duration::QUICK);
 }
 
-static LolipopCounterTestSuite
+static LollipopCounterTestSuite
     g_lollipopCounterTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/packetbb-test-suite.cc ns-3.42/src/network/test/packetbb-test-suite.cc
--- ns-3.41/src/network/test/packetbb-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/packetbb-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -123,7 +123,7 @@
 };
 
 PbbTestSuite::PbbTestSuite()
-    : TestSuite("packetbb-test-suite", UNIT)
+    : TestSuite("packetbb-test-suite", Type::UNIT)
 {
     /* Test 1
      *    ,------------------
@@ -136,7 +136,8 @@
     {
         Ptr<PbbPacket> packet = Create<PbbPacket>();
         uint8_t buffer[] = {0x00};
-        AddTestCase(new PbbTestCase("1", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("1", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 2
@@ -152,7 +153,8 @@
         Ptr<PbbPacket> packet = Create<PbbPacket>();
         packet->SetSequenceNumber(2);
         uint8_t buffer[] = {0x08, 0x00, 0x02};
-        AddTestCase(new PbbTestCase("2", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("2", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 3
@@ -171,7 +173,7 @@
     Ptr<PbbPacket> packet = Create<PbbPacket> ();
     packet->SetSequenceNumber (3);
     uint8_t buffer[] = { 0x0c, 0x00, 0x03, 0x00, 0x00};
-    AddTestCase (new PbbTestCase ("3", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+    AddTestCase (new PbbTestCase ("3", packet, buffer, sizeof(buffer)), TestCase::Duration::QUICK);
   }
 #endif
 
@@ -197,7 +199,8 @@
 
         packet->TlvPushBack(tlv);
         uint8_t buffer[] = {0x0c, 0x00, 0x04, 0x00, 0x02, 0x01, 0x00};
-        AddTestCase(new PbbTestCase("4", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("4", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 5
@@ -230,7 +233,8 @@
         packet->TlvPushBack(tlv2);
 
         uint8_t buffer[] = {0x0c, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x02, 0x80, 0x64};
-        AddTestCase(new PbbTestCase("5", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("5", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 6
@@ -284,7 +288,8 @@
             0x03,
             0x04,
         };
-        AddTestCase(new PbbTestCase("6", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("6", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 7
@@ -443,7 +448,8 @@
             0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
             0x29, 0x2a, 0x2b, 0x2c,
         };
-        AddTestCase(new PbbTestCase("7", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("7", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 8
@@ -493,7 +499,8 @@
             0x00,
             0x00,
         };
-        AddTestCase(new PbbTestCase("8", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("8", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 9
@@ -546,7 +553,8 @@
             0x03, 0x00, 0x06, 0x00, 0x00, 0x02, 0x83, 0x00, /* [14] used to be 0x80 */
             0x0a, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("9", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("9", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 10
@@ -601,7 +609,8 @@
             0x03, 0x00, 0x06, 0x00, 0x00, 0x02, 0xa3, 0x00, /* [14] used to be 0xa0 */
             0x0b, 0x0a, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("10", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("10", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 11
@@ -658,7 +667,8 @@
             0x00, 0x06, 0x00, 0x00, 0x02, 0xe3, 0x00, /* [14] used to be 0xe0 */
             0x0c, 0x0a, 0x00, 0x00, 0x01, 0xff, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("11", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("11", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 12
@@ -717,7 +727,8 @@
             0x00, 0x00, 0x02, 0xf3, 0x00, /* [14] - 0xf0 */
             0x0e, 0x0a, 0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("12", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("12", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 13
@@ -776,7 +787,8 @@
             0x00, 0x00, 0x02, 0xf3, 0x00, /* [14] - 0xf0 */
             0x0e, 0x0a, 0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("13", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("13", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 14
@@ -844,7 +856,8 @@
             0x08, 0x00, 0x02, 0x01, 0x00, 0x02, 0xf3, 0x00, 0x0e, 0x0a, /* [16] - 0xf0 */
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("14", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("14", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 15
@@ -922,7 +935,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x01,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("15", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("15", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 16
@@ -1000,7 +1014,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x01,
             0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("16", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("16", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 17
@@ -1078,7 +1093,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x01,
             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("17", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("17", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 18
@@ -1156,7 +1172,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x01,
             0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("18", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("18", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 19
@@ -1234,7 +1251,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x01,
             0x00, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("19", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("19", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 20
@@ -1314,7 +1332,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x02,
             0x80, 0x03, 0x0a, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("20", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("20", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 21
@@ -1394,7 +1413,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x02, 0xc0,
             0x01, 0x0a, 0x01, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("21", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("21", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 22
@@ -1484,7 +1504,8 @@
             0x00, 0x00, 0x01, 0xff, 0x01, 0x30, 0x39, 0x00, 0x00, 0x02, 0xc0, 0x01, 0x0a, 0x01,
             0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x20, 0x03, 0x0a, 0x0b, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("22", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("22", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 23
@@ -1586,7 +1607,8 @@
             0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x0a,
             0x00, 0x00, 0x06, 0x20, 0x20, 0x10, 0x18, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("23", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("23", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 24
@@ -1695,7 +1717,8 @@
             0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x0a,
             0x00, 0x00, 0x06, 0x20, 0x20, 0x10, 0x18, 0x00, 0x02, 0x01, 0x00,
         };
-        AddTestCase(new PbbTestCase("24", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("24", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 25
@@ -1806,7 +1829,8 @@
             0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x0a,
             0x00, 0x00, 0x06, 0x20, 0x20, 0x10, 0x18, 0x00, 0x03, 0x01, 0x40, 0x01,
         };
-        AddTestCase(new PbbTestCase("25", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("25", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 26
@@ -1919,7 +1943,8 @@
             0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x06,
             0x20, 0x20, 0x10, 0x18, 0x00, 0x04, 0x01, 0x20, 0x01, 0x03,
         };
-        AddTestCase(new PbbTestCase("26", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("26", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 27
@@ -2037,7 +2062,8 @@
             0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x0a, 0x00, 0x00, 0x06, 0x20, 0x20, 0x10,
             0x18, 0x00, 0x08, 0x01, 0x34, 0x01, 0x03, 0x03, 0x01, 0x02, 0x03,
         };
-        AddTestCase(new PbbTestCase("27", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("27", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 28
@@ -2274,7 +2300,8 @@
             0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
             0x2c,
         };
-        AddTestCase(new PbbTestCase("28", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("28", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 29
@@ -2309,7 +2336,8 @@
             0x00,
             0x00,
         };
-        AddTestCase(new PbbTestCase("29", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("29", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 30
@@ -2341,7 +2369,8 @@
             0x00, 0x01, 0x8f, 0x00, 0x16, 0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("30", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("30", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 31
@@ -2383,7 +2412,8 @@
             0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("31", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("31", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 32
@@ -2427,7 +2457,8 @@
             0x80, 0x0f, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("32", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("32", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 33
@@ -2471,7 +2502,8 @@
             0xc0, 0x0d, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("33", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("33", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 34
@@ -2525,7 +2557,8 @@
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02,
             0x00, 0x11, 0x00, 0x00, 0x02, 0xa0, 0x01, 0x00, 0x0e, 0x10, 0x11, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("34", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("34", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 35
@@ -2592,7 +2625,8 @@
             0x00, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x40, 0x30, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("35", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("35", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 36
@@ -2874,7 +2908,8 @@
             0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x40, 0x30, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("36", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("36", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 
     /* Test 37
@@ -3156,7 +3191,8 @@
             0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x40, 0x30, 0x00, 0x00,
         };
-        AddTestCase(new PbbTestCase("37", packet, buffer, sizeof(buffer)), TestCase::QUICK);
+        AddTestCase(new PbbTestCase("37", packet, buffer, sizeof(buffer)),
+                    TestCase::Duration::QUICK);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/packet-metadata-test.cc ns-3.42/src/network/test/packet-metadata-test.cc
--- ns-3.41/src/network/test/packet-metadata-test.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/packet-metadata-test.cc	2024-05-29 15:29:47.148073700 -0700
@@ -894,9 +894,9 @@
 };
 
 PacketMetadataTestSuite::PacketMetadataTestSuite()
-    : TestSuite("packet-metadata", UNIT)
+    : TestSuite("packet-metadata", Type::UNIT)
 {
-    AddTestCase(new PacketMetadataTest, TestCase::QUICK);
+    AddTestCase(new PacketMetadataTest, TestCase::Duration::QUICK);
 }
 
 static PacketMetadataTestSuite g_packetMetadataTest; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/packet-socket-apps-test-suite.cc ns-3.42/src/network/test/packet-socket-apps-test-suite.cc
--- ns-3.41/src/network/test/packet-socket-apps-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/packet-socket-apps-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -130,9 +130,9 @@
 {
   public:
     PacketSocketAppsTestSuite()
-        : TestSuite("packet-socket-apps", UNIT)
+        : TestSuite("packet-socket-apps", Type::UNIT)
     {
-        AddTestCase(new PacketSocketAppsTest, TestCase::QUICK);
+        AddTestCase(new PacketSocketAppsTest, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/packet-test-suite.cc ns-3.42/src/network/test/packet-test-suite.cc
--- ns-3.41/src/network/test/packet-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/packet-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -1281,10 +1281,10 @@
 };
 
 PacketTestSuite::PacketTestSuite()
-    : TestSuite("packet", UNIT)
+    : TestSuite("packet", Type::UNIT)
 {
-    AddTestCase(new PacketTest, TestCase::QUICK);
-    AddTestCase(new PacketTagListTest, TestCase::QUICK);
+    AddTestCase(new PacketTest, TestCase::Duration::QUICK);
+    AddTestCase(new PacketTagListTest, TestCase::Duration::QUICK);
 }
 
 static PacketTestSuite g_packetTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/pcap-file-test-suite.cc ns-3.42/src/network/test/pcap-file-test-suite.cc
--- ns-3.41/src/network/test/pcap-file-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/pcap-file-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -1388,16 +1388,16 @@
 };
 
 PcapFileTestSuite::PcapFileTestSuite()
-    : TestSuite("pcap-file", UNIT)
+    : TestSuite("pcap-file", Type::UNIT)
 {
     SetDataDir(NS_TEST_SOURCEDIR);
-    AddTestCase(new WriteModeCreateTestCase, TestCase::QUICK);
-    AddTestCase(new ReadModeCreateTestCase, TestCase::QUICK);
-    // AddTestCase (new AppendModeCreateTestCase, TestCase::QUICK);
-    AddTestCase(new FileHeaderTestCase, TestCase::QUICK);
-    AddTestCase(new RecordHeaderTestCase, TestCase::QUICK);
-    AddTestCase(new ReadFileTestCase, TestCase::QUICK);
-    AddTestCase(new DiffTestCase, TestCase::QUICK);
+    AddTestCase(new WriteModeCreateTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ReadModeCreateTestCase, TestCase::Duration::QUICK);
+    // AddTestCase (new AppendModeCreateTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new FileHeaderTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new RecordHeaderTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ReadFileTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new DiffTestCase, TestCase::Duration::QUICK);
 }
 
 static PcapFileTestSuite pcapFileTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/sequence-number-test-suite.cc ns-3.42/src/network/test/sequence-number-test-suite.cc
--- ns-3.41/src/network/test/sequence-number-test-suite.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/sequence-number-test-suite.cc	2024-05-29 15:29:47.148073700 -0700
@@ -226,9 +226,9 @@
 {
   public:
     SequenceNumberTestSuite()
-        : TestSuite("sequence-number", UNIT)
+        : TestSuite("sequence-number", Type::UNIT)
     {
-        AddTestCase(new SequenceNumberTestCase(), TestCase::QUICK);
+        AddTestCase(new SequenceNumberTestCase(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/test/test-data-rate.cc ns-3.42/src/network/test/test-data-rate.cc
--- ns-3.41/src/network/test/test-data-rate.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/test/test-data-rate.cc	2024-05-29 15:29:47.152073600 -0700
@@ -282,10 +282,10 @@
 };
 
 DataRateTestSuite::DataRateTestSuite()
-    : TestSuite("data-rate", UNIT)
+    : TestSuite("data-rate", Type::UNIT)
 {
-    AddTestCase(new DataRateTestCase1(), TestCase::QUICK);
-    AddTestCase(new DataRateTestCase2(), TestCase::QUICK);
+    AddTestCase(new DataRateTestCase1(), TestCase::Duration::QUICK);
+    AddTestCase(new DataRateTestCase2(), TestCase::Duration::QUICK);
 }
 
 static DataRateTestSuite sDataRateTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/address-utils.cc ns-3.42/src/network/utils/address-utils.cc
--- ns-3.41/src/network/utils/address-utils.cc	2024-02-09 14:44:08.421793700 -0800
+++ ns-3.42/src/network/utils/address-utils.cc	2024-05-29 15:29:47.152073600 -0700
@@ -19,6 +19,7 @@
 #include "address-utils.h"
 
 #include "inet-socket-address.h"
+#include "inet6-socket-address.h"
 
 #include "ns3/log.h"
 
@@ -146,7 +147,23 @@
         Ipv4Address ipv4 = inetAddr.GetIpv4();
         return ipv4.IsMulticast();
     }
-    // IPv6 case can go here, in future
+    else if (Ipv4Address::IsMatchingType(ad))
+    {
+        Ipv4Address ipv4 = Ipv4Address::ConvertFrom(ad);
+        return ipv4.IsMulticast();
+    }
+    else if (Inet6SocketAddress::IsMatchingType(ad))
+    {
+        Inet6SocketAddress inetAddr = Inet6SocketAddress::ConvertFrom(ad);
+        Ipv6Address ipv6 = inetAddr.GetIpv6();
+        return ipv6.IsMulticast();
+    }
+    else if (Ipv6Address::IsMatchingType(ad))
+    {
+        Ipv6Address ipv6 = Ipv6Address::ConvertFrom(ad);
+        return ipv6.IsMulticast();
+    }
+
     return false;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/data-rate.cc ns-3.42/src/network/utils/data-rate.cc
--- ns-3.41/src/network/utils/data-rate.cc	2024-02-09 14:44:08.425794000 -0800
+++ ns-3.42/src/network/utils/data-rate.cc	2024-05-29 15:29:47.152073600 -0700
@@ -43,62 +43,22 @@
         double r;
         iss >> r;
         std::string trailer = s.substr(n, std::string::npos);
-        if (trailer == "bps")
+        if (trailer == "bps" || trailer == "b/s")
         {
             // bit/s
             *v = (uint64_t)r;
         }
-        else if (trailer == "b/s")
-        {
-            // bit/s
-            *v = (uint64_t)r;
-        }
-        else if (trailer == "Bps")
-        {
-            // byte/s
-            *v = (uint64_t)(r * 8);
-        }
-        else if (trailer == "B/s")
+        else if (trailer == "Bps" || trailer == "B/s")
         {
             // byte/s
             *v = (uint64_t)(r * 8);
         }
-        else if (trailer == "kbps")
-        {
-            // kilobits/s
-            *v = (uint64_t)(r * 1000);
-        }
-        else if (trailer == "kb/s")
+        else if (trailer == "kbps" || trailer == "kb/s" || trailer == "Kbps" || trailer == "Kb/s")
         {
             // kilobits/s
             *v = (uint64_t)(r * 1000);
         }
-        else if (trailer == "Kbps")
-        {
-            // kilobits/s
-            *v = (uint64_t)(r * 1000);
-        }
-        else if (trailer == "Kb/s")
-        {
-            // kilobits/s
-            *v = (uint64_t)(r * 1000);
-        }
-        else if (trailer == "kBps")
-        {
-            // kiloByte/s
-            *v = (uint64_t)(r * 8000);
-        }
-        else if (trailer == "kB/s")
-        {
-            // KiloByte/s
-            *v = (uint64_t)(r * 8000);
-        }
-        else if (trailer == "KBps")
-        {
-            // kiloByte/s
-            *v = (uint64_t)(r * 8000);
-        }
-        else if (trailer == "KB/s")
+        else if (trailer == "kBps" || trailer == "kB/s" || trailer == "KBps" || trailer == "KB/s")
         {
             // KiloByte/s
             *v = (uint64_t)(r * 8000);
@@ -113,22 +73,12 @@
             // kibibyte/s
             *v = (uint64_t)(r * 8192);
         }
-        else if (trailer == "Mbps")
-        {
-            // MegaBits/s
-            *v = (uint64_t)(r * 1000000);
-        }
-        else if (trailer == "Mb/s")
+        else if (trailer == "Mbps" || trailer == "Mb/s")
         {
             // MegaBits/s
             *v = (uint64_t)(r * 1000000);
         }
-        else if (trailer == "MBps")
-        {
-            // MegaBytes/s
-            *v = (uint64_t)(r * 8000000);
-        }
-        else if (trailer == "MB/s")
+        else if (trailer == "MBps" || trailer == "MB/s")
         {
             // MegaBytes/s
             *v = (uint64_t)(r * 8000000);
@@ -143,22 +93,12 @@
             // MebiByte/s
             *v = (uint64_t)(r * 1048576 * 8);
         }
-        else if (trailer == "Gbps")
+        else if (trailer == "Gbps" || trailer == "Gb/s")
         {
             // GigaBit/s
             *v = (uint64_t)(r * 1000000000);
         }
-        else if (trailer == "Gb/s")
-        {
-            // GigaBit/s
-            *v = (uint64_t)(r * 1000000000);
-        }
-        else if (trailer == "GBps")
-        {
-            // GigaByte/s
-            *v = (uint64_t)(r * 8 * 1000000000);
-        }
-        else if (trailer == "GB/s")
+        else if (trailer == "GBps" || trailer == "GB/s")
         {
             // GigaByte/s
             *v = (uint64_t)(r * 8 * 1000000000);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/inet-socket-address.cc ns-3.42/src/network/utils/inet-socket-address.cc
--- ns-3.41/src/network/utils/inet-socket-address.cc	2024-02-09 14:44:08.425794000 -0800
+++ ns-3.42/src/network/utils/inet-socket-address.cc	2024-05-29 15:29:47.152073600 -0700
@@ -29,40 +29,35 @@
 
 InetSocketAddress::InetSocketAddress(Ipv4Address ipv4, uint16_t port)
     : m_ipv4(ipv4),
-      m_port(port),
-      m_tos(0)
+      m_port(port)
 {
     NS_LOG_FUNCTION(this << ipv4 << port);
 }
 
 InetSocketAddress::InetSocketAddress(Ipv4Address ipv4)
     : m_ipv4(ipv4),
-      m_port(0),
-      m_tos(0)
+      m_port(0)
 {
     NS_LOG_FUNCTION(this << ipv4);
 }
 
 InetSocketAddress::InetSocketAddress(const char* ipv4, uint16_t port)
     : m_ipv4(Ipv4Address(ipv4)),
-      m_port(port),
-      m_tos(0)
+      m_port(port)
 {
     NS_LOG_FUNCTION(this << ipv4 << port);
 }
 
 InetSocketAddress::InetSocketAddress(const char* ipv4)
     : m_ipv4(Ipv4Address(ipv4)),
-      m_port(0),
-      m_tos(0)
+      m_port(0)
 {
     NS_LOG_FUNCTION(this << ipv4);
 }
 
 InetSocketAddress::InetSocketAddress(uint16_t port)
     : m_ipv4(Ipv4Address::GetAny()),
-      m_port(port),
-      m_tos(0)
+      m_port(port)
 {
     NS_LOG_FUNCTION(this << port);
 }
@@ -81,13 +76,6 @@
     return m_ipv4;
 }
 
-uint8_t
-InetSocketAddress::GetTos() const
-{
-    NS_LOG_FUNCTION(this);
-    return m_tos;
-}
-
 void
 InetSocketAddress::SetPort(uint16_t port)
 {
@@ -102,18 +90,11 @@
     m_ipv4 = address;
 }
 
-void
-InetSocketAddress::SetTos(uint8_t tos)
-{
-    NS_LOG_FUNCTION(this << tos);
-    m_tos = tos;
-}
-
 bool
 InetSocketAddress::IsMatchingType(const Address& address)
 {
     NS_LOG_FUNCTION(&address);
-    return address.CheckCompatible(GetType(), 7);
+    return address.CheckCompatible(GetType(), 6);
 }
 
 InetSocketAddress::operator Address() const
@@ -125,26 +106,23 @@
 InetSocketAddress::ConvertTo() const
 {
     NS_LOG_FUNCTION(this);
-    uint8_t buf[7];
+    uint8_t buf[6];
     m_ipv4.Serialize(buf);
     buf[4] = m_port & 0xff;
     buf[5] = (m_port >> 8) & 0xff;
-    buf[6] = m_tos;
-    return Address(GetType(), buf, 7);
+    return Address(GetType(), buf, 6);
 }
 
 InetSocketAddress
 InetSocketAddress::ConvertFrom(const Address& address)
 {
     NS_LOG_FUNCTION(&address);
-    NS_ASSERT(address.CheckCompatible(GetType(), 7));
-    uint8_t buf[7];
+    NS_ASSERT(address.CheckCompatible(GetType(), 6)); /* 4 (address) + 2  (port) */
+    uint8_t buf[6];
     address.CopyTo(buf);
     Ipv4Address ipv4 = Ipv4Address::Deserialize(buf);
     uint16_t port = buf[4] | (buf[5] << 8);
-    uint8_t tos = buf[6];
     InetSocketAddress inet(ipv4, port);
-    inet.SetTos(tos);
     return inet;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/inet-socket-address.h ns-3.42/src/network/utils/inet-socket-address.h
--- ns-3.41/src/network/utils/inet-socket-address.h	2024-02-09 14:44:08.425794000 -0800
+++ ns-3.42/src/network/utils/inet-socket-address.h	2024-05-29 15:29:47.152073600 -0700
@@ -77,10 +77,6 @@
      * \returns the ipv4 address
      */
     Ipv4Address GetIpv4() const;
-    /**
-     * \returns the ToS
-     */
-    uint8_t GetTos() const;
 
     /**
      * \param port the new port number.
@@ -90,10 +86,6 @@
      * \param address the new ipv4 address
      */
     void SetIpv4(Ipv4Address address);
-    /**
-     * \param tos the new ToS.
-     */
-    void SetTos(uint8_t tos);
 
     /**
      * \param address address to test
@@ -131,7 +123,6 @@
     static uint8_t GetType();
     Ipv4Address m_ipv4; //!< the IPv4 address
     uint16_t m_port;    //!< the port
-    uint8_t m_tos;      //!< the ToS
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/ipv6-address.cc ns-3.42/src/network/utils/ipv6-address.cc
--- ns-3.41/src/network/utils/ipv6-address.cc	2024-02-09 14:44:08.425794000 -0800
+++ ns-3.42/src/network/utils/ipv6-address.cc	2024-05-29 15:29:47.152073600 -0700
@@ -44,6 +44,43 @@
 extern "C"
 { /* } */
 #endif
+    /**
+     * \brief Mix hash keys in-place for lookuphash
+     *
+     * \param a first word of the hash key
+     * \param b second word of the hash key
+     * \param c third word of the hash key
+     */
+    void mixHashKey(uint32_t& a, uint32_t& b, uint32_t& c)
+    {
+        (a) -= (b);
+        (a) -= (c);
+        (a) ^= ((c) >> 13);
+        (b) -= (c);
+        (b) -= (a);
+        (b) ^= ((a) << 8);
+        (c) -= (a);
+        (c) -= (b);
+        (c) ^= ((b) >> 13);
+        (a) -= (b);
+        (a) -= (c);
+        (a) ^= ((c) >> 12);
+        (b) -= (c);
+        (b) -= (a);
+        (b) ^= ((a) << 16);
+        (c) -= (a);
+        (c) -= (b);
+        (c) ^= ((b) >> 5);
+        (a) -= (b);
+        (a) -= (c);
+        (a) ^= ((c) >> 3);
+        (b) -= (c);
+        (b) -= (a);
+        (b) ^= ((a) << 10);
+        (c) -= (a);
+        (c) -= (b);
+        (c) ^= ((b) >> 15);
+    }
 
     /**
      * \brief Get a hash key.
@@ -56,36 +93,6 @@
     static uint32_t lookuphash(unsigned char* k, uint32_t length, uint32_t level)
     {
         NS_LOG_FUNCTION(k << length << level);
-#define mix(a, b, c)                                                                               \
-    ({                                                                                             \
-        (a) -= (b);                                                                                \
-        (a) -= (c);                                                                                \
-        (a) ^= ((c) >> 13);                                                                        \
-        (b) -= (c);                                                                                \
-        (b) -= (a);                                                                                \
-        (b) ^= ((a) << 8);                                                                         \
-        (c) -= (a);                                                                                \
-        (c) -= (b);                                                                                \
-        (c) ^= ((b) >> 13);                                                                        \
-        (a) -= (b);                                                                                \
-        (a) -= (c);                                                                                \
-        (a) ^= ((c) >> 12);                                                                        \
-        (b) -= (c);                                                                                \
-        (b) -= (a);                                                                                \
-        (b) ^= ((a) << 16);                                                                        \
-        (c) -= (a);                                                                                \
-        (c) -= (b);                                                                                \
-        (c) ^= ((b) >> 5);                                                                         \
-        (a) -= (b);                                                                                \
-        (a) -= (c);                                                                                \
-        (a) ^= ((c) >> 3);                                                                         \
-        (b) -= (c);                                                                                \
-        (b) -= (a);                                                                                \
-        (b) ^= ((a) << 10);                                                                        \
-        (c) -= (a);                                                                                \
-        (c) -= (b);                                                                                \
-        (c) ^= ((b) >> 15);                                                                        \
-    })
 
         typedef uint32_t ub4; /* unsigned 4-byte quantities */
         uint32_t a = 0;
@@ -104,7 +111,7 @@
             a += (k[0] + ((ub4)k[1] << 8) + ((ub4)k[2] << 16) + ((ub4)k[3] << 24));
             b += (k[4] + ((ub4)k[5] << 8) + ((ub4)k[6] << 16) + ((ub4)k[7] << 24));
             c += (k[8] + ((ub4)k[9] << 8) + ((ub4)k[10] << 16) + ((ub4)k[11] << 24));
-            mix(a, b, c);
+            mixHashKey(a, b, c);
             k += 12;
             len -= 12;
         }
@@ -137,9 +144,7 @@
             a += k[0];
             /* case 0: nothing left to add */
         }
-        mix(a, b, c);
-
-#undef mix
+        mixHashKey(a, b, c);
 
         /* report the result */
         return c;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/lollipop-counter.h ns-3.42/src/network/utils/lollipop-counter.h
--- ns-3.41/src/network/utils/lollipop-counter.h	2024-02-09 14:44:08.425794000 -0800
+++ ns-3.42/src/network/utils/lollipop-counter.h	2024-05-29 15:29:47.152073600 -0700
@@ -279,11 +279,7 @@
             return false;
         }
 
-        if (lhs > rhs)
-        {
-            return false;
-        }
-        else if (lhs == rhs)
+        if (lhs > rhs || lhs == rhs)
         {
             return false;
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/network/utils/simple-net-device.cc ns-3.42/src/network/utils/simple-net-device.cc
--- ns-3.41/src/network/utils/simple-net-device.cc	2024-02-09 14:44:08.429793800 -0800
+++ ns-3.42/src/network/utils/simple-net-device.cc	2024-05-29 15:29:47.152073600 -0700
@@ -380,7 +380,7 @@
 SimpleNetDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION(this);
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
@@ -450,7 +450,7 @@
 
     if (m_queue->Enqueue(p))
     {
-        if (m_queue->GetNPackets() == 1 && !FinishTransmissionEvent.IsRunning())
+        if (m_queue->GetNPackets() == 1 && !FinishTransmissionEvent.IsPending())
         {
             StartTransmission();
         }
@@ -467,7 +467,7 @@
     {
         return;
     }
-    NS_ASSERT_MSG(!FinishTransmissionEvent.IsRunning(),
+    NS_ASSERT_MSG(!FinishTransmissionEvent.IsPending(),
                   "Tried to transmit a packet while another transmission was in progress");
     Ptr<Packet> packet = m_queue->Dequeue();
 
@@ -544,7 +544,7 @@
     m_node = nullptr;
     m_receiveErrorModel = nullptr;
     m_queue->Dispose();
-    if (FinishTransmissionEvent.IsRunning())
+    if (FinishTransmissionEvent.IsPending())
     {
         FinishTransmissionEvent.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/nix-vector-routing/test/nix-test.cc ns-3.42/src/nix-vector-routing/test/nix-test.cc
--- ns-3.41/src/nix-vector-routing/test/nix-test.cc	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/nix-vector-routing/test/nix-test.cc	2024-05-29 15:29:47.156073600 -0700
@@ -403,9 +403,9 @@
 {
   public:
     NixVectorRoutingTestSuite()
-        : TestSuite("nix-vector-routing", UNIT)
+        : TestSuite("nix-vector-routing", Type::UNIT)
     {
-        AddTestCase(new NixVectorRoutingTest(), TestCase::QUICK);
+        AddTestCase(new NixVectorRoutingTest(), TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/olsr/model/olsr-header.cc ns-3.42/src/olsr/model/olsr-header.cc
--- ns-3.41/src/olsr/model/olsr-header.cc	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/olsr/model/olsr-header.cc	2024-05-29 15:29:47.156073600 -0700
@@ -604,7 +604,7 @@
     {
         Ipv4Address address(i.ReadNtohU32());
         Ipv4Mask mask(i.ReadNtohU32());
-        this->associations.push_back((Association){address, mask});
+        this->associations.push_back(Association{address, mask});
     }
     return messageSize;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/olsr/model/olsr-routing-protocol.cc ns-3.42/src/olsr/model/olsr-routing-protocol.cc
--- ns-3.41/src/olsr/model/olsr-routing-protocol.cc	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/olsr/model/olsr-routing-protocol.cc	2024-05-29 15:29:47.156073600 -0700
@@ -1952,14 +1952,14 @@
     }
     // If the tuple does not already exist, add it to the list of local HNA associations.
     NS_LOG_INFO("Adding HNA association for network " << networkAddr << "/" << netmask << ".");
-    m_state.InsertAssociation((Association){networkAddr, netmask});
+    m_state.InsertAssociation(Association{networkAddr, netmask});
 }
 
 void
 RoutingProtocol::RemoveHostNetworkAssociation(Ipv4Address networkAddr, Ipv4Mask netmask)
 {
     NS_LOG_INFO("Removing HNA association for network " << networkAddr << "/" << netmask << ".");
-    m_state.EraseAssociation((Association){networkAddr, netmask});
+    m_state.EraseAssociation(Association{networkAddr, netmask});
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/olsr/test/olsr-header-test-suite.cc ns-3.42/src/olsr/test/olsr-header-test-suite.cc
--- ns-3.41/src/olsr/test/olsr-header-test-suite.cc	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/olsr/test/olsr-header-test-suite.cc	2024-05-29 15:29:47.156073600 -0700
@@ -306,9 +306,9 @@
     olsr::MessageHeader::Hna& hnaIn = msgIn.GetHna();
 
     hnaIn.associations.push_back(
-        (olsr::MessageHeader::Hna::Association){Ipv4Address("1.2.3.4"), Ipv4Mask("255.255.255.0")});
+        olsr::MessageHeader::Hna::Association{Ipv4Address("1.2.3.4"), Ipv4Mask("255.255.255.0")});
     hnaIn.associations.push_back(
-        (olsr::MessageHeader::Hna::Association){Ipv4Address("1.2.3.5"), Ipv4Mask("255.255.0.0")});
+        olsr::MessageHeader::Hna::Association{Ipv4Address("1.2.3.5"), Ipv4Mask("255.255.0.0")});
     packet.AddHeader(msgIn);
 
     olsr::MessageHeader msgOut;
@@ -339,13 +339,13 @@
 };
 
 OlsrTestSuite::OlsrTestSuite()
-    : TestSuite("routing-olsr-header", UNIT)
+    : TestSuite("routing-olsr-header", Type::UNIT)
 {
-    AddTestCase(new OlsrHnaTestCase(), TestCase::QUICK);
-    AddTestCase(new OlsrTcTestCase(), TestCase::QUICK);
-    AddTestCase(new OlsrHelloTestCase(), TestCase::QUICK);
-    AddTestCase(new OlsrMidTestCase(), TestCase::QUICK);
-    AddTestCase(new OlsrEmfTestCase(), TestCase::QUICK);
+    AddTestCase(new OlsrHnaTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new OlsrTcTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new OlsrHelloTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new OlsrMidTestCase(), TestCase::Duration::QUICK);
+    AddTestCase(new OlsrEmfTestCase(), TestCase::Duration::QUICK);
 }
 
 static OlsrTestSuite g_olsrTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/olsr/test/olsr-routing-protocol-test-suite.cc ns-3.42/src/olsr/test/olsr-routing-protocol-test-suite.cc
--- ns-3.41/src/olsr/test/olsr-routing-protocol-test-suite.cc	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/olsr/test/olsr-routing-protocol-test-suite.cc	2024-05-29 15:29:47.156073600 -0700
@@ -187,9 +187,9 @@
 };
 
 OlsrProtocolTestSuite::OlsrProtocolTestSuite()
-    : TestSuite("routing-olsr", UNIT)
+    : TestSuite("routing-olsr", Type::UNIT)
 {
-    AddTestCase(new OlsrMprTestCase(), TestCase::QUICK);
+    AddTestCase(new OlsrMprTestCase(), TestCase::Duration::QUICK);
 }
 
 static OlsrProtocolTestSuite g_olsrProtocolTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/olsr/test/regression-test-suite.cc ns-3.42/src/olsr/test/regression-test-suite.cc
--- ns-3.41/src/olsr/test/regression-test-suite.cc	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/olsr/test/regression-test-suite.cc	2024-05-29 15:29:47.156073600 -0700
@@ -34,12 +34,12 @@
 {
   public:
     RegressionTestSuite()
-        : TestSuite("routing-olsr-regression", SYSTEM)
+        : TestSuite("routing-olsr-regression", Type::SYSTEM)
     {
         SetDataDir(NS_TEST_SOURCEDIR);
-        AddTestCase(new HelloRegressionTest, TestCase::QUICK);
-        AddTestCase(new TcRegressionTest, TestCase::QUICK);
-        AddTestCase(new Bug780Test, TestCase::QUICK);
+        AddTestCase(new HelloRegressionTest, TestCase::Duration::QUICK);
+        AddTestCase(new TcRegressionTest, TestCase::Duration::QUICK);
+        AddTestCase(new Bug780Test, TestCase::Duration::QUICK);
     }
 };
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/openflow/examples/openflow-switch.py ns-3.42/src/openflow/examples/openflow-switch.py
--- ns-3.41/src/openflow/examples/openflow-switch.py	2024-02-09 14:44:08.433793800 -0800
+++ ns-3.42/src/openflow/examples/openflow-switch.py	2024-05-29 15:29:47.156073600 -0700
@@ -53,7 +53,7 @@
 switchNode = csmaSwitch.Get(0)
 swtch = ns.OpenFlowSwitchHelper()
 controller = ns.ofi.DropController()
-# controller = ns.CreateObject("ns3::ofi::LearningController")
+# controller = ns.CreateObject[ns.ofi.LearningController]()
 swtch.Install(switchNode, switchDevices, controller)
 # controller->SetAttribute("ExpirationTime", TimeValue(timeout))
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/openflow/model/openflow-switch-net-device.cc ns-3.42/src/openflow/model/openflow-switch-net-device.cc
--- ns-3.41/src/openflow/model/openflow-switch-net-device.cc	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/openflow/model/openflow-switch-net-device.cc	2024-05-29 15:29:47.156073600 -0700
@@ -283,7 +283,7 @@
 OpenFlowSwitchNetDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION_NOARGS();
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/openflow/test/openflow-switch-test-suite.cc ns-3.42/src/openflow/test/openflow-switch-test-suite.cc
--- ns-3.41/src/openflow/test/openflow-switch-test-suite.cc	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/openflow/test/openflow-switch-test-suite.cc	2024-05-29 15:29:47.156073600 -0700
@@ -205,9 +205,9 @@
 };
 
 SwitchTestSuite::SwitchTestSuite()
-    : TestSuite("openflow", UNIT)
+    : TestSuite("openflow", Type::UNIT)
 {
-    AddTestCase(new SwitchFlowTableTestCase, TestCase::QUICK);
+    AddTestCase(new SwitchFlowTableTestCase, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/point-to-point/model/point-to-point-channel.h ns-3.42/src/point-to-point/model/point-to-point-channel.h
--- ns-3.41/src/point-to-point/model/point-to-point-channel.h	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/point-to-point/model/point-to-point-channel.h	2024-05-29 15:29:47.156073600 -0700
@@ -197,14 +197,9 @@
         /** \brief Create the link, it will be in INITIALIZING state
          *
          */
-        Link()
-            : m_state(INITIALIZING),
-              m_src(nullptr),
-              m_dst(nullptr)
-        {
-        }
+        Link() = default;
 
-        WireState m_state;                //!< State of the link
+        WireState m_state{INITIALIZING};  //!< State of the link
         Ptr<PointToPointNetDevice> m_src; //!< First NetDevice
         Ptr<PointToPointNetDevice> m_dst; //!< Second NetDevice
     };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/point-to-point/model/point-to-point-net-device.cc ns-3.42/src/point-to-point/model/point-to-point-net-device.cc
--- ns-3.41/src/point-to-point/model/point-to-point-net-device.cc	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/point-to-point/model/point-to-point-net-device.cc	2024-05-29 15:29:47.160073800 -0700
@@ -471,7 +471,7 @@
 PointToPointNetDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION(this);
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/point-to-point/test/point-to-point-test.cc ns-3.42/src/point-to-point/test/point-to-point-test.cc
--- ns-3.41/src/point-to-point/test/point-to-point-test.cc	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/point-to-point/test/point-to-point-test.cc	2024-05-29 15:29:47.160073800 -0700
@@ -152,9 +152,9 @@
 };
 
 PointToPointTestSuite::PointToPointTestSuite()
-    : TestSuite("devices-point-to-point", UNIT)
+    : TestSuite("devices-point-to-point", Type::UNIT)
 {
-    AddTestCase(new PointToPointTest, TestCase::QUICK);
+    AddTestCase(new PointToPointTest, TestCase::Duration::QUICK);
 }
 
 static PointToPointTestSuite g_pointToPointTestSuite; //!< The testsuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/CMakeLists.txt ns-3.42/src/propagation/CMakeLists.txt
--- ns-3.41/src/propagation/CMakeLists.txt	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/propagation/CMakeLists.txt	2024-05-29 15:29:47.160073800 -0700
@@ -40,5 +40,5 @@
     test/probabilistic-v2v-channel-condition-model-test.cc
     test/propagation-loss-model-test-suite.cc
     test/three-gpp-propagation-loss-model-test-suite.cc
-    test/three-gpp-propagation-loss-model-test-suite.cc
+    test/three-gpp-ntn-propagation-loss-model-test-suite.cc
 )
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/doc/propagation.rst ns-3.42/src/propagation/doc/propagation.rst
--- ns-3.41/src/propagation/doc/propagation.rst	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/propagation/doc/propagation.rst	2024-05-29 15:29:47.160073800 -0700
@@ -42,6 +42,10 @@
       * ThreeGppUMaPropagationLossModel
       * ThreeGppUmiStreetCanyonPropagationLossModel
       * ThreeGppIndoorOfficePropagationLossModel
+      * ThreeGppNTNDenseUrbanPropagationLossModel
+      * ThreeGppNTNUrbanPropagationLossModel
+      * ThreeGppNTNSuburbanPropagationLossModel
+      * ThreeGppNTNRuralPropagationLossModel
 
 Other models could be available thanks to other modules, e.g., the ``building`` module.
 
@@ -746,6 +750,47 @@
 :cpp:class:`ThreeGppIndoorOfficePropagationLossModelTestCase` compute the path loss between two nodes and compares it with the value obtained using the formulas in 3GPP TR 38.901 [38901]_, Table 7.4.1-1.
 The test case :cpp:class:`ThreeGppShadowingTestCase` checks if the shadowing is correctly computed by testing the deviation of the overall propagation loss from the path loss. The test is carried out for all the scenarios, both in LOS and NLOS condition.
 
+ThreeGppNTNPropagationLossModel
+===============================
+
+Four different classes have been derived from the base class :cpp:class:`ThreeGppPropagationLossModel`
+to support Non-Terrestrial Networks, one for each scenario presented in 3GPP TR 38.811 [38811]_, i.e.,
+dense urban, urban, suburban and rural.
+
+*Implemented features:*
+
+  * Line of Sight and Not Line of Sight (LOS/NLOS) probability models (3GPP TR 38.811, Sec. 6.6.1)
+  * Path loss, shadowing models and clutter loss (3GPP TR 38.811, Sec. 6.6.2)
+  * Atmospheric absorption model (3GPP TR 38.811, Sec. 6.6.4)
+  * Ionospheric and tropospheric scintillation (3GPP TR 38.811, Sec. 6.6.6)
+  * All the features already implemented in `ThreeGppPropagationLossModel <index.html#threegpppropagationlossmodel>`_
+
+
+ThreeGppNTNDenseUrbanPropagationLossModel
+`````````````````````````````````````````
+This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP
+TR 38.811 [38811]_, Table 6.6.2-1 for the Dense Urban scenario. It
+supports frequencies between 0.5 and 100 GHz.
+
+ThreeGppNTNUrbanPropagationLossModel
+````````````````````````````````````
+This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP
+TR 38.811 [38811]_, Table 6.6.2-2 for the Urban scenario. It
+supports frequencies between 0.5 and 100 GHz.
+
+ThreeGppNTNSuburbanPropagationLossModel
+```````````````````````````````````````
+This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP
+TR 38.811 [38811]_, Table 6.6.2-3 for the Suburban scenario. It
+supports frequencies between 0.5 and 100 GHz.
+
+ThreeGppNTNRuralPropagationLossModel
+````````````````````````````````````
+This class implements the LOS/NLOS path loss and shadow fading models described in 3GPP
+TR 38.811 [38811]_, Table 6.6.2-3 for the Rural scenario. It
+supports frequencies between 0.5 and 100 GHz.
+
+
 ChannelConditionModel
 *********************
 
@@ -778,30 +823,60 @@
 ThreeGppChannelConditionModel
 =============================
 This is the base class for the 3GPP channel condition models.
-It provides the possibility to updated the condition of each channel periodically,
+It provides the possibility to update the condition of each channel periodically,
 after a given time period which can be configured through the attribute "UpdatePeriod".
 If "UpdatePeriod" is set to 0, the channel condition is never updated.
 It has five derived classes implementing the channel condition models described in 3GPP TR 38.901 [38901]_ for different propagation scenarios.
 
 ThreeGppRmaChannelConditionModel
 ````````````````````````````````
-This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the RMa scenario.
+This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the RMa scenario.
 
 ThreeGppUmaChannelConditionModel
 ````````````````````````````````
-This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMa scenario.
+This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMa scenario.
 
 ThreeGppUmiStreetCanyonChannelConditionModel
 ````````````````````````````````````````````
-This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMi-Street Canyon scenario.
+This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the UMi-Street Canyon scenario.
 
 ThreeGppIndoorMixedOfficeChannelConditionModel
 ``````````````````````````````````````````````
-This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Mixed office scenario.
+This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Mixed office scenario.
 
 ThreeGppIndoorOpenOfficeChannelConditionModel
 `````````````````````````````````````````````
-This implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Open office scenario.
+This class implements the statistical channel condition model described in 3GPP TR 38.901 [38901]_, Table 7.4.2-1, for the Indoor-Open office scenario.
+
+ThreeGppNTNChannelConditionModel
+================================
+This is the base class for the 3GPP NTN channel condition models.
+It provides the possibility to update the condition of each channel periodically,
+after a given time period which can be configured through the attribute "UpdatePeriod".
+If "UpdatePeriod" is set to 0, the channel condition is never updated.
+It has four derived classes implementing the channel condition models described in 3GPP TR 38.811 [38811]_
+for the different propagation scenarios. i.e., dense urban, urban, suburban and rural.
+
+ThreeGppDenseUrbanChannelConditionModel
+```````````````````````````````````````
+This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_,
+Table 6.6.1-1, for the Dense Urban scenario.
+
+ThreeGppUrbanChannelConditionModel
+``````````````````````````````````
+This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_,
+Table 6.6.1-1, for the Urban scenario.
+
+ThreeGppSuburbanStreetCanyonChannelConditionModel
+`````````````````````````````````````````````````
+This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_,
+Table 6.6.1-1, for the Suburban scenario.
+
+ThreeGppRuralChannelConditionModel
+``````````````````````````````````
+This class implements the statistical channel condition model described in 3GPP TR 38.811 [38811]_,
+Table 6.6.1-1, for the Rural office scenario.
+
 
 Testing
 =======
@@ -1036,3 +1111,5 @@
 .. [Boban2016Modeling]  M. Boban,  X. Gong, and  W. Xu, “Modeling the evolution
    of line-of-sight blockage for V2V channels,” in IEEE 84th Vehicular Technology
    Conference (VTC-Fall), 2016.
+
+.. [38811] 3GPP. 2018. TR 38.811, Study on New Radio (NR) to support non-terrestrial networks, V15.4.0. (2020-09).
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/channel-condition-model.cc ns-3.42/src/propagation/model/channel-condition-model.cc
--- ns-3.41/src/propagation/model/channel-condition-model.cc	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/propagation/model/channel-condition-model.cc	2024-05-29 15:29:47.160073800 -0700
@@ -20,14 +20,60 @@
 
 #include "ns3/boolean.h"
 #include "ns3/double.h"
+#include "ns3/geocentric-constant-position-mobility-model.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
 #include "ns3/node.h"
+#include "ns3/pointer.h"
 #include "ns3/simulator.h"
 #include "ns3/string.h"
 
 #include <cmath>
 
+namespace
+{
+
+/// NTN Dense Urban LOS probabilities from table 6.6.1-1 of 3GPP 38.811
+const std::map<int, double> DenseUrbanLOSProb{
+    {10, {28.2}},
+    {20, {33.1}},
+    {30, {39.8}},
+    {40, {46.8}},
+    {50, {53.7}},
+    {60, {61.2}},
+    {70, {73.8}},
+    {80, {82.0}},
+    {90, {98.1}},
+};
+
+/// NTN Urban LOS probabilities from table 6.6.1-1 of 3GPP 38.811
+const std::map<int, double> UrbanLOSProb{
+    {10, {24.6}},
+    {20, {38.6}},
+    {30, {49.3}},
+    {40, {61.3}},
+    {50, {72.6}},
+    {60, {80.5}},
+    {70, {91.9}},
+    {80, {96.8}},
+    {90, {99.2}},
+};
+
+/// NTN Suburban LOS probabilities from table 6.6.1-1 of 3GPP 38.811
+const std::map<int, double> SuburbanRuralLOSProb{
+    {10, {78.2}},
+    {20, {86.9}},
+    {30, {91.9}},
+    {40, {92.9}},
+    {50, {93.5}},
+    {60, {94.0}},
+    {70, {94.9}},
+    {80, {95.2}},
+    {90, {99.8}},
+};
+
+} // namespace
+
 namespace ns3
 {
 
@@ -537,6 +583,29 @@
     return key;
 }
 
+std::tuple<double, double>
+ThreeGppChannelConditionModel::GetQuantizedElevationAngle(Ptr<const MobilityModel> a,
+                                                          Ptr<const MobilityModel> b)
+{
+    Ptr<MobilityModel> aMobNonConst = ConstCast<MobilityModel>(a);
+    Ptr<MobilityModel> bMobNonConst = ConstCast<MobilityModel>(b);
+
+    // check if aMob and bMob are of type GeocentricConstantPositionMobilityModel
+    auto aNTNMob = DynamicCast<GeocentricConstantPositionMobilityModel>(aMobNonConst);
+    auto bNTNMob = DynamicCast<GeocentricConstantPositionMobilityModel>(bMobNonConst);
+    NS_ASSERT_MSG(aNTNMob && bNTNMob,
+                  "Mobility Models need to be of type Geocentric for NTN scenarios");
+
+    double elevAngle = aNTNMob->GetElevationAngle(bNTNMob);
+    // Round the elevation angle into a two-digits integer between 10 and 90, as specified in
+    // Sec. 6.6.1, 3GPP TR 38.811 v15.4.0
+    int elevAngleQuantized = (elevAngle < 10) ? 10 : round(elevAngle / 10) * 10;
+    NS_ASSERT_MSG((elevAngleQuantized >= 10) && (elevAngleQuantized <= 90),
+                  "Invalid elevation angle!");
+
+    return std::make_tuple(elevAngle, elevAngleQuantized);
+};
+
 // ------------------------------------------------------------------------- //
 
 NS_OBJECT_ENSURE_REGISTERED(ThreeGppRmaChannelConditionModel);
@@ -829,4 +898,100 @@
     return pLos;
 }
 
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNDenseUrbanChannelConditionModel);
+
+TypeId
+ThreeGppNTNDenseUrbanChannelConditionModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNDenseUrbanChannelConditionModel")
+                            .SetParent<ThreeGppChannelConditionModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNDenseUrbanChannelConditionModel>();
+    return tid;
+}
+
+double
+ThreeGppNTNDenseUrbanChannelConditionModel::ComputePlos(Ptr<const MobilityModel> a,
+                                                        Ptr<const MobilityModel> b) const
+{
+    // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1).
+    // The elevation angle is first quantized to one of the reference angles.
+    auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b);
+    return DenseUrbanLOSProb.at(quantizedElevAngle);
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNUrbanChannelConditionModel);
+
+TypeId
+ThreeGppNTNUrbanChannelConditionModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNUrbanChannelConditionModel")
+                            .SetParent<ThreeGppChannelConditionModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNUrbanChannelConditionModel>();
+    return tid;
+}
+
+double
+ThreeGppNTNUrbanChannelConditionModel::ComputePlos(Ptr<const MobilityModel> a,
+                                                   Ptr<const MobilityModel> b) const
+{
+    // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1).
+    // The elevation angle is first quantized to one of the reference angles.
+    auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b);
+    return UrbanLOSProb.at(quantizedElevAngle);
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNSuburbanChannelConditionModel);
+
+TypeId
+ThreeGppNTNSuburbanChannelConditionModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNSuburbanChannelConditionModel")
+                            .SetParent<ThreeGppChannelConditionModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNSuburbanChannelConditionModel>();
+    return tid;
+}
+
+double
+ThreeGppNTNSuburbanChannelConditionModel::ComputePlos(Ptr<const MobilityModel> a,
+                                                      Ptr<const MobilityModel> b) const
+{
+    // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1).
+    // The elevation angle is first quantized to one of the reference angles.
+    auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b);
+    return SuburbanRuralLOSProb.at(quantizedElevAngle);
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNRuralChannelConditionModel);
+
+TypeId
+ThreeGppNTNRuralChannelConditionModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNRuralChannelConditionModel")
+                            .SetParent<ThreeGppChannelConditionModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNRuralChannelConditionModel>();
+    return tid;
+}
+
+double
+ThreeGppNTNRuralChannelConditionModel::ComputePlos(Ptr<const MobilityModel> a,
+                                                   Ptr<const MobilityModel> b) const
+{
+    // Compute the LOS probability (see 3GPP TR 38.811, Table 6.6.1-1).
+    // The elevation angle is first quantized to one of the reference angles.
+    auto [elevAngle, quantizedElevAngle] = GetQuantizedElevationAngle(a, b);
+    return SuburbanRuralLOSProb.at(quantizedElevAngle);
+}
+
 } // end namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/channel-condition-model.h ns-3.42/src/propagation/model/channel-condition-model.h
--- ns-3.41/src/propagation/model/channel-condition-model.h	2024-02-09 14:44:08.453794000 -0800
+++ ns-3.42/src/propagation/model/channel-condition-model.h	2024-05-29 15:29:47.160073800 -0700
@@ -24,6 +24,7 @@
 #include "ns3/random-variable-stream.h"
 #include "ns3/vector.h"
 
+#include <map>
 #include <unordered_map>
 
 namespace ns3
@@ -483,6 +484,27 @@
      */
     int64_t AssignStreams(int64_t stream) override;
 
+    /**
+     * Computes and quantizes the elevation angle to a two-digits integer in [10, 90].
+     * Asserts that the provided mobility models are of the expected type, i.e.,
+     * GeocentricConstantPositionMobilityModel, and that the quantized
+     * angle is in the expected range [10, 90].
+     *
+     * \param a mobility model
+     * \param b mobility model
+     * \return the tuple [elevation angle, quantized elevation angle] between a and b
+     */
+    static std::tuple<double, double> GetQuantizedElevationAngle(Ptr<const MobilityModel> a,
+                                                                 Ptr<const MobilityModel> b);
+
+    /**
+     * \brief Computes the 2D distance between two 3D vectors
+     * \param a the first 3D vector
+     * \param b the second 3D vector
+     * \return the 2D distance between a and b
+     */
+    static double Calculate2dDistance(const Vector& a, const Vector& b);
+
   protected:
     void DoDispose() override;
 
@@ -497,14 +519,6 @@
         INVALID
     };
 
-    /**
-     * \brief Computes the 2D distance between two 3D vectors
-     * \param a the first 3D vector
-     * \param b the second 3D vector
-     * \return the 2D distance between a and b
-     */
-    static double Calculate2dDistance(const Vector& a, const Vector& b);
-
     Ptr<UniformRandomVariable> m_uniformVar; //!< uniform random variable
 
   private:
@@ -781,6 +795,154 @@
      */
     double ComputePlos(Ptr<const MobilityModel> a, Ptr<const MobilityModel> b) const override;
 };
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Computes the channel condition for the NTN Dense Urban Scenario
+ *
+ * Computes the channel condition following the specifications for the
+ * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811
+ */
+class ThreeGppNTNDenseUrbanChannelConditionModel : public ThreeGppChannelConditionModel
+{
+  public:
+    /**
+     *  Register this type.
+     *  \return The object TypeId.
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor for the ThreeGppNTNDenseUrbanChannelConditionModel class
+     */
+    ThreeGppNTNDenseUrbanChannelConditionModel() = default;
+
+    /**
+     * Destructor for the ThreeGppNTNDenseUrbanChannelConditionModel class
+     */
+    ~ThreeGppNTNDenseUrbanChannelConditionModel() override = default;
+
+  private:
+    /**
+     * \copydoc ThreeGppChannelConditionModel::ComputePlos
+     *
+     * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811
+     * for the NTN Dense Urban scenario.
+     */
+    double ComputePlos(Ptr<const MobilityModel> a, Ptr<const MobilityModel> b) const override;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Computes the channel condition for the NTN Urban Scenario
+ *
+ * Computes the channel condition following the specifications for the
+ * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811
+ */
+class ThreeGppNTNUrbanChannelConditionModel : public ThreeGppChannelConditionModel
+{
+  public:
+    /**
+     *  Register this type.
+     *  \return The object TypeId.
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor for the ThreeGppNTNUrbanChannelConditionModel class
+     */
+    ThreeGppNTNUrbanChannelConditionModel() = default;
+
+    /**
+     * Destructor for the ThreeGppNTNUrbanChannelConditionModel class
+     */
+    ~ThreeGppNTNUrbanChannelConditionModel() override = default;
+
+  private:
+    /**
+     * \copydoc ThreeGppChannelConditionModel::ComputePlos
+     *
+     * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811
+     * for the NTN Urban scenario.
+     */
+    double ComputePlos(Ptr<const MobilityModel> a, Ptr<const MobilityModel> b) const override;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Computes the channel condition for the NTN Suburban Scenario
+ *
+ * Computes the channel condition following the specifications for the
+ * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811
+ */
+class ThreeGppNTNSuburbanChannelConditionModel : public ThreeGppChannelConditionModel
+{
+  public:
+    /**
+     *  Register this type.
+     *  \return The object TypeId.
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor for the ThreeGppNTNSuburbanChannelConditionModel class
+     */
+    ThreeGppNTNSuburbanChannelConditionModel() = default;
+
+    /**
+     * Destructor for the ThreeGppNTNSuburbanChannelConditionModel class
+     */
+    ~ThreeGppNTNSuburbanChannelConditionModel() override = default;
+
+  private:
+    /**
+     * \copydoc ThreeGppChannelConditionModel::ComputePlos
+     *
+     * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811
+     * for the NTN Suburban scenario.
+     */
+    double ComputePlos(Ptr<const MobilityModel> a, Ptr<const MobilityModel> b) const override;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Computes the channel condition for the NTN Rural Scenario
+ *
+ * Computes the channel condition following the specifications for the
+ * Indoor Mixed Office scenario reported in Table 6.6.1-1 of 3GPP TR 38.811
+ */
+class ThreeGppNTNRuralChannelConditionModel : public ThreeGppChannelConditionModel
+{
+  public:
+    /**
+     *  Register this type.
+     *  \return The object TypeId.
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor for the ThreeGppNTNRuralChannelConditionModel class
+     */
+    ThreeGppNTNRuralChannelConditionModel() = default;
+
+    /**
+     * Destructor for the ThreeGppNTNRuralChannelConditionModel class
+     */
+    ~ThreeGppNTNRuralChannelConditionModel() override = default;
+
+  private:
+    /**
+     * \copydoc ThreeGppChannelConditionModel::ComputePlos
+     *
+     * Compute the LOS probability as specified in Table 6.6.1-1 of 3GPP TR 38.811
+     * for the NTN Rural scenario.
+     */
+    double ComputePlos(Ptr<const MobilityModel> a, Ptr<const MobilityModel> b) const override;
+};
 
 } // namespace ns3
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/jakes-process.h ns-3.42/src/propagation/model/jakes-process.h
--- ns-3.41/src/propagation/model/jakes-process.h	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/jakes-process.h	2024-05-29 15:29:47.160073800 -0700
@@ -31,7 +31,7 @@
 class JakesPropagationLossModel;
 
 /**
- * \ingroup fading
+ * \ingroup propagation
  *
  * \brief Implementation for a single path Stationary Jakes propagation loss model.
  *
@@ -45,9 +45,8 @@
  * \f[ X_s(t) = \frac{2}{\sqrt{M}}\sum_{n=1}^{M}\sin(\psi_n)\cos(\omega_d t\cos(\alpha_n)+\phi_n)\f]
  * with
  * \f[ \alpha_n = \frac{2\pi n - \pi + \theta}{4M},  n=1,2, \ldots,M\f]
- * where
- *\f$\theta\f$, \f$\phi\f$, and \f$\psi_n\f$ are statically independent and uniformly distributed
- *over \f$[-\pi, \pi)\f$ for all \f$n\f$.
+ * where \f$\theta\f$, \f$\phi\f$, and \f$\psi_n\f$ are
+ * statically independent and uniformly distributed over \f$[-\pi, \pi)\f$ for all \f$n\f$.
  *
  *
  * [1] Y. R. Zheng and C. Xiao, "Simulation Models With Correct
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/propagation-loss-model.cc ns-3.42/src/propagation/model/propagation-loss-model.cc
--- ns-3.41/src/propagation/model/propagation-loss-model.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/propagation-loss-model.cc	2024-05-29 15:29:47.160073800 -0700
@@ -161,9 +161,10 @@
                                    &FriisPropagationLossModel::GetFrequency),
                 MakeDoubleChecker<double>())
             .AddAttribute("SystemLoss",
-                          "The system loss",
+                          "The system loss (linear factor >= 1, not in dB)",
                           DoubleValue(1.0),
-                          MakeDoubleAccessor(&FriisPropagationLossModel::m_systemLoss),
+                          MakeDoubleAccessor(&FriisPropagationLossModel::SetSystemLoss,
+                                             &FriisPropagationLossModel::GetSystemLoss),
                           MakeDoubleChecker<double>())
             .AddAttribute("MinLoss",
                           "The minimum value (dB) of the total loss, used at short ranges.",
@@ -181,6 +182,7 @@
 void
 FriisPropagationLossModel::SetSystemLoss(double systemLoss)
 {
+    NS_ABORT_MSG_UNLESS(systemLoss >= 1, "System loss less than 1 corresponds to gain");
     m_systemLoss = systemLoss;
 }
 
@@ -308,9 +310,10 @@
                                    &TwoRayGroundPropagationLossModel::GetFrequency),
                 MakeDoubleChecker<double>())
             .AddAttribute("SystemLoss",
-                          "The system loss",
+                          "The system loss (linear factor >= 1, not in dB)",
                           DoubleValue(1.0),
-                          MakeDoubleAccessor(&TwoRayGroundPropagationLossModel::m_systemLoss),
+                          MakeDoubleAccessor(&TwoRayGroundPropagationLossModel::SetSystemLoss,
+                                             &TwoRayGroundPropagationLossModel::GetSystemLoss),
                           MakeDoubleChecker<double>())
             .AddAttribute(
                 "MinDistance",
@@ -334,6 +337,7 @@
 void
 TwoRayGroundPropagationLossModel::SetSystemLoss(double systemLoss)
 {
+    NS_ABORT_MSG_UNLESS(systemLoss >= 1, "System loss less than 1 corresponds to gain");
     m_systemLoss = systemLoss;
 }
 
@@ -530,6 +534,8 @@
     double distance = a->GetDistanceFrom(b);
     if (distance <= m_referenceDistance)
     {
+        NS_LOG_DEBUG("distance=" << distance << "m, reference-attenuation=" << -m_referenceLoss
+                                 << "dB, no further attenuation");
         return txPowerDbm - m_referenceLoss;
     }
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/propagation-loss-model.h ns-3.42/src/propagation/model/propagation-loss-model.h
--- ns-3.41/src/propagation/model/propagation-loss-model.h	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/propagation-loss-model.h	2024-05-29 15:29:47.160073800 -0700
@@ -271,9 +271,11 @@
      */
     void SetFrequency(double frequency);
     /**
-     * \param systemLoss (dimension-less)
+     * \param systemLoss (linear factor, dimension-less)
      *
      * Set the system loss used by the Friis propagation model.
+     * Value should be greater than or equal to 1; the default of 1
+     * corresponds to no system loss.
      */
     void SetSystemLoss(double systemLoss);
 
@@ -295,7 +297,7 @@
      */
     double GetFrequency() const;
     /**
-     * \returns the current system loss (dimension-less)
+     * \returns the current system loss (linear factor, dimension-less)
      */
     double GetSystemLoss() const;
 
@@ -321,7 +323,7 @@
 
     double m_lambda;     //!< the carrier wavelength
     double m_frequency;  //!< the carrier frequency
-    double m_systemLoss; //!< the system loss
+    double m_systemLoss; //!< the system loss (linear factor)
     double m_minLoss;    //!< the minimum loss
 };
 
@@ -376,9 +378,11 @@
     void SetFrequency(double frequency);
 
     /**
-     * \param systemLoss (dimension-less)
+     * \param systemLoss (linear factor, dimension-less)
      *
      * Set the system loss used by the TwoRayGround propagation model.
+     * Value should be greater than or equal to 1; the default of 1
+     * corresponds to no system loss.
      */
     void SetSystemLoss(double systemLoss);
     /**
@@ -399,7 +403,7 @@
     double GetFrequency() const;
 
     /**
-     * \returns the current system loss (dimension-less)
+     * \returns the current system loss (linear factor, dimension-less)
      */
     double GetSystemLoss() const;
     /**
@@ -431,7 +435,7 @@
 
     double m_lambda;       //!< the carrier wavelength
     double m_frequency;    //!< the carrier frequency
-    double m_systemLoss;   //!< the system loss
+    double m_systemLoss;   //!< the system loss (linear factor)
     double m_minDistance;  //!< minimum distance for the model
     double m_heightAboveZ; //!< antenna height above the node's Z coordinate
 };
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/three-gpp-propagation-loss-model.cc ns-3.42/src/propagation/model/three-gpp-propagation-loss-model.cc
--- ns-3.41/src/propagation/model/three-gpp-propagation-loss-model.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/three-gpp-propagation-loss-model.cc	2024-05-29 15:29:47.160073800 -0700
@@ -22,6 +22,7 @@
 
 #include "ns3/boolean.h"
 #include "ns3/double.h"
+#include "ns3/geocentric-constant-position-mobility-model.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
 #include "ns3/node.h"
@@ -30,14 +31,246 @@
 
 #include <cmath>
 
-namespace ns3
+namespace
+{
+/**
+ * The enumerator used for code clarity when performing parameter assignment in the GetLoss Methods
+ */
+enum SFCL_params
+{
+    S_LOS_sigF,
+    S_NLOS_sigF,
+    S_NLOS_CL,
+    Ka_LOS_sigF,
+    Ka_NLOS_sigF,
+    Ka_NLOS_CL,
+};
+
+/**
+ * The map containing the 3GPP value regarding Shadow Fading and Clutter Loss tables for the
+ * NTN Dense Urban scenario
+ */
+const std::map<int, std::vector<float>> SFCL_DenseUrban{
+    {10, {3.5, 15.5, 34.3, 2.9, 17.1, 44.3}},
+    {20, {3.4, 13.9, 30.9, 2.4, 17.1, 39.9}},
+    {30, {2.9, 12.4, 29.0, 2.7, 15.6, 37.5}},
+    {40, {3.0, 11.7, 27.7, 2.4, 14.6, 35.8}},
+    {50, {3.1, 10.6, 26.8, 2.4, 14.2, 34.6}},
+    {60, {2.7, 10.5, 26.2, 2.7, 12.6, 33.8}},
+    {70, {2.5, 10.1, 25.8, 2.6, 12.1, 33.3}},
+    {80, {2.3, 9.2, 25.5, 2.8, 12.3, 33.0}},
+    {90, {1.2, 9.2, 25.5, 0.6, 12.3, 32.9}},
+};
+
+/**
+ * The map containing the 3GPP value regarding Shadow Fading and Clutter Loss tables for the
+ * NTN Urban scenario
+ */
+const std::map<int, std::vector<float>> SFCL_Urban{
+    {10, {4, 6, 34.3, 4, 6, 44.3}},
+    {20, {4, 6, 30.9, 4, 6, 39.9}},
+    {30, {4, 6, 29.0, 4, 6, 37.5}},
+    {40, {4, 6, 27.7, 4, 6, 35.8}},
+    {50, {4, 6, 26.8, 4, 6, 34.6}},
+    {60, {4, 6, 26.2, 4, 6, 33.8}},
+    {70, {4, 6, 25.8, 4, 6, 33.3}},
+    {80, {4, 6, 25.5, 4, 6, 33.0}},
+    {90, {4, 6, 25.5, 4, 6, 32.9}},
+};
+
+/**
+ * The map containing the 3GPP value regarding Shadow Fading and Clutter Loss tables for the
+ * NTN Suburban and Rural scenarios
+ */
+const std::map<int, std::vector<float>> SFCL_SuburbanRural{
+    {10, {1.79, 8.93, 19.52, 1.9, 10.7, 29.5}},
+    {20, {1.14, 9.08, 18.17, 1.6, 10.0, 24.6}},
+    {30, {1.14, 8.78, 18.42, 1.9, 11.2, 21.9}},
+    {40, {0.92, 10.25, 18.28, 2.3, 11.6, 20.0}},
+    {50, {1.42, 10.56, 18.63, 2.7, 11.8, 18.7}},
+    {60, {1.56, 10.74, 17.68, 3.1, 10.8, 17.8}},
+    {70, {0.85, 10.17, 16.5, 3.0, 10.8, 17.2}},
+    {80, {0.72, 11.52, 16.3, 3.6, 10.8, 16.9}},
+    {90, {0.72, 11.52, 16.3, 0.4, 10.8, 16.8}},
+};
+
+/**
+ * Array containing the attenuation given by atmospheric absorption. 100 samples are selected for
+ * frequencies from 1GHz to 100GHz. In order to get the atmospheric absorption loss for a given
+ * frequency f: 1- round f to the closest integer between 0 and 100. 2- use the obtained integer to
+ * access the corresponding element in the array, that will give the attenuation at that frequency.
+ * Data is obtained form ITU-R P.676 Figure 6.
+ */
+const double atmosphericAbsorption[101] = {
+    0,        0.0300,   0.0350,  0.0380,  0.0390,  0.0410,  0.0420,  0.0450,  0.0480,   0.0500,
+    0.0530,   0.0587,   0.0674,  0.0789,  0.0935,  0.1113,  0.1322,  0.1565,  0.1841,   0.2153,
+    0.2500,   0.3362,   0.4581,  0.5200,  0.5200,  0.5000,  0.4500,  0.3850,  0.3200,   0.2700,
+    0.2500,   0.2517,   0.2568,  0.2651,  0.2765,  0.2907,  0.3077,  0.3273,  0.3493,   0.3736,
+    0.4000,   0.4375,   0.4966,  0.5795,  0.6881,  0.8247,  0.9912,  1.1900,  1.4229,   1.6922,
+    2.0000,   4.2654,   10.1504, 19.2717, 31.2457, 45.6890, 62.2182, 80.4496, 100.0000, 140.0205,
+    170.0000, 100.0000, 78.1682, 59.3955, 43.5434, 30.4733, 20.0465, 12.1244, 6.5683,   3.2397,
+    2.0000,   1.7708,   1.5660,  1.3858,  1.2298,  1.0981,  0.9905,  0.9070,  0.8475,   0.8119,
+    0.8000,   0.8000,   0.8000,  0.8000,  0.8000,  0.8000,  0.8000,  0.8000,  0.8000,   0.8000,
+    0.8000,   0.8029,   0.8112,  0.8243,  0.8416,  0.8625,  0.8864,  0.9127,  0.9408,   0.9701,
+    1.0000};
+
+/**
+ * Map containing the Tropospheric attenuation in dB with 99% probability at 20 GHz in Toulouse
+ * used for tropospheric scintillation losses. From Table 6.6.6.2.1-1 of 3GPP TR 38.811.
+ */
+const std::map<int, float> troposphericScintillationLoss{
+    {10, {1.08}},
+    {20, {0.48}},
+    {30, {0.30}},
+    {40, {0.22}},
+    {50, {0.17}},
+    {60, {0.13}},
+    {70, {0.12}},
+    {80, {0.12}},
+    {90, {0.12}},
+};
+
+/**
+ * @brief Get the base station and user terminal relative distances and heights
+ *
+ * @param a the mobility model of terminal a
+ * @param b the mobility model of terminal b
+ *
+ * @return The tuple [dist2D, dist3D, hBs, hUt], where dist2D and dist3D
+ * are the 2D and 3D distances between a and b, respectively, hBs is the bigger
+ * height and hUt the smallest.
+ */
+std::tuple<double, double, double, double>
+GetBsUtDistancesAndHeights(ns3::Ptr<const ns3::MobilityModel> a,
+                           ns3::Ptr<const ns3::MobilityModel> b)
+{
+    auto aPos = a->GetPosition();
+    auto bPos = b->GetPosition();
+    double distance2D = ns3::ThreeGppChannelConditionModel::Calculate2dDistance(aPos, bPos);
+    double distance3D = ns3::CalculateDistance(aPos, bPos);
+    double hBs = std::max(aPos.z, bPos.z);
+    double hUt = std::min(aPos.z, bPos.z);
+    return std::make_tuple(distance2D, distance3D, hBs, hUt);
+};
+
+/**
+ * @brief Get the base station and user terminal heights for the UmiStreetCanyon scenario
+ *
+ * @param heightA the first height in meters
+ * @param heightB the second height in meters
+ *
+ * @return The tuple [hBs, hUt], where hBs is assumed to be = 10 and hUt other height.
+ */
+std::tuple<double, double>
+GetBsUtHeightsUmiStreetCanyon(double heightA, double heightB)
+{
+    double hBs = (heightA == 10) ? heightA : heightB;
+    double hUt = (heightA == 10) ? heightB : heightA;
+    return std::make_tuple(hBs, hUt);
+};
+
+/**
+ * @brief Computes the free-space path loss using the formula described in 3GPP TR 38.811,
+ * Table 6.6.2
+ *
+ * @param freq the operating frequency
+ * @param dist3d the 3D distance between the communicating nodes
+ *
+ * @return the path loss for NTN scenarios
+ */
+double
+ComputeNtnPathloss(double freq, double dist3d)
+{
+    return 32.45 + 20 * log10(freq / 1e9) + 20 * log10(dist3d);
+};
+
+/**
+ * @brief Computes the atmospheric absorption loss using the formula described in 3GPP TR 38.811,
+ * Sec 6.6.4
+ *
+ * @param freq the operating frequency
+ * @param elevAngle the elevation angle between the communicating nodes
+ *
+ * @return the atmospheric absorption loss for NTN scenarios
+ */
+double
+ComputeAtmosphericAbsorptionLoss(double freq, double elevAngle)
 {
+    double loss = 0;
+    if ((elevAngle < 10 && freq > 1e9) || freq >= 10e9)
+    {
+        int roundedFreq = round(freq / 10e8);
+        loss += atmosphericAbsorption[roundedFreq] / sin(elevAngle * (M_PI / 180));
+    }
 
-NS_LOG_COMPONENT_DEFINE("ThreeGppPropagationLossModel");
+    return loss;
+};
 
-static const double M_C = 3.0e8; //!< propagation velocity in free space
+/**
+ * @brief Computes the ionospheric plus tropospheric scintillation loss using the formulas
+ * described in 3GPP TR 38.811, Sec 6.6.6.1-4 and 6.6.6.2, respectively.
+ *
+ * @param freq the operating frequency
+ * @param elevAngleQuantized the quantized elevation angle between the communicating nodes
+ *
+ * @return the ionospheric plus tropospheric scintillation loss for NTN scenarios
+ */
+double
+ComputeIonosphericPlusTroposphericScintillationLoss(double freq, double elevAngleQuantized)
+{
+    double loss = 0;
+    if (freq < 6e9)
+    {
+        // Ionospheric
+        loss = 6.22 / (pow(freq / 1e9, 1.5));
+    }
+    else
+    {
+        // Tropospheric
+        loss = troposphericScintillationLoss.at(elevAngleQuantized);
+    }
+    return loss;
+};
 
-// ------------------------------------------------------------------------- //
+/**
+ * @brief Computes the clutter loss using the formula
+ * described in 3GPP TR 38.811, Sec 6.6.6.1-4 and 6.6.6.2, respectively.
+ *
+ * @param freq the operating frequency
+ * @param elevAngleQuantized the quantized elevation angle between the communicating nodes
+ * @param sfcl the nested map containing the Shadow Fading and
+ *         Clutter Loss values for the NTN Suburban and Rural scenario
+ *
+ * @return the clutter loss for NTN scenarios
+ */
+double
+ComputeClutterLoss(double freq,
+                   const std::map<int, std::vector<float>>* sfcl,
+                   double elevAngleQuantized)
+{
+    double loss = 0;
+    if (freq < 13.0e9)
+    {
+        loss += (*sfcl).at(elevAngleQuantized)[SFCL_params::S_NLOS_CL]; // Get the Clutter Loss for
+                                                                        // the S Band
+    }
+    else
+    {
+        loss += (*sfcl).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_CL]; // Get the Clutter Loss for
+                                                                         // the Ka Band
+    }
+
+    return loss;
+};
+
+constexpr double M_C = 3.0e8; //!< propagation velocity in free space
+
+} // namespace
+
+namespace ns3
+{
+
+NS_LOG_COMPONENT_DEFINE("ThreeGppPropagationLossModel");
 
 NS_OBJECT_ENSURE_REGISTERED(ThreeGppPropagationLossModel);
 
@@ -165,17 +398,8 @@
     NS_ASSERT_MSG(m_channelConditionModel, "First set the channel condition model");
     Ptr<ChannelCondition> cond = m_channelConditionModel->GetChannelCondition(a, b);
 
-    // compute the 2D distance between a and b
-    double distance2d = Calculate2dDistance(a->GetPosition(), b->GetPosition());
-
-    // compute the 3D distance between a and b
-    double distance3d = CalculateDistance(a->GetPosition(), b->GetPosition());
-
-    // compute hUT and hBS
-    std::pair<double, double> heights = GetUtAndBsHeights(a->GetPosition().z, b->GetPosition().z);
-
     double rxPow = txPowerDbm;
-    rxPow -= GetLoss(cond, distance2d, distance3d, heights.first, heights.second);
+    rxPow -= GetLoss(cond, a, b);
 
     if (m_shadowingEnabled)
     {
@@ -183,21 +407,10 @@
     }
 
     // get o2i losses
-    if (cond->GetO2iCondition() == ChannelCondition::O2iConditionValue::O2I &&
-        m_buildingPenLossesEnabled)
-    {
-        if (IsO2iLowPenetrationLoss(cond))
-        {
-            rxPow -= GetO2iLowPenetrationLoss(a, b, cond->GetLosCondition());
-        }
-        else
-        {
-            rxPow -= GetO2iHighPenetrationLoss(a, b, cond->GetLosCondition());
-        }
-    }
-    else if (cond->GetO2iCondition() == ChannelCondition::O2iConditionValue::I2I &&
-             cond->GetLosCondition() == ChannelCondition::LosConditionValue::NLOS &&
-             m_buildingPenLossesEnabled)
+    if (m_buildingPenLossesEnabled &&
+        ((cond->GetO2iCondition() == ChannelCondition::O2iConditionValue::O2I) ||
+         (cond->GetO2iCondition() == ChannelCondition::O2iConditionValue::I2I &&
+          cond->GetLosCondition() == ChannelCondition::LosConditionValue::NLOS)))
     {
         if (IsO2iLowPenetrationLoss(cond))
         {
@@ -214,28 +427,24 @@
 
 double
 ThreeGppPropagationLossModel::GetLoss(Ptr<ChannelCondition> cond,
-                                      double distance2d,
-                                      double distance3d,
-                                      double hUt,
-                                      double hBs) const
+                                      Ptr<MobilityModel> a,
+                                      Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
     double loss = 0;
-    if (cond->GetLosCondition() == ChannelCondition::LosConditionValue::LOS)
-    {
-        loss = GetLossLos(distance2d, distance3d, hUt, hBs);
-    }
-    else if (cond->GetLosCondition() == ChannelCondition::LosConditionValue::NLOSv)
-    {
-        loss = GetLossNlosv(distance2d, distance3d, hUt, hBs);
-    }
-    else if (cond->GetLosCondition() == ChannelCondition::LosConditionValue::NLOS)
-    {
-        loss = GetLossNlos(distance2d, distance3d, hUt, hBs);
-    }
-    else
+    switch (cond->GetLosCondition())
     {
+    case ChannelCondition::LosConditionValue::LOS:
+        loss = GetLossLos(a, b);
+        break;
+    case ChannelCondition::LosConditionValue::NLOSv:
+        loss = GetLossNlosv(a, b);
+        break;
+    case ChannelCondition::LosConditionValue::NLOS:
+        loss = GetLossNlos(a, b);
+        break;
+    default:
         NS_FATAL_ERROR("Unknown channel condition");
     }
 
@@ -402,10 +611,7 @@
 }
 
 double
-ThreeGppPropagationLossModel::GetLossNlosv(double distance2D,
-                                           double distance3D,
-                                           double hUt,
-                                           double hBs) const
+ThreeGppPropagationLossModel::GetLossNlosv(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
     NS_FATAL_ERROR("Unsupported channel condition (NLOSv)");
@@ -469,17 +675,6 @@
     return shadowingValue;
 }
 
-std::pair<double, double>
-ThreeGppPropagationLossModel::GetUtAndBsHeights(double za, double zb) const
-{
-    // The default implementation assumes that the tallest node is the BS and the
-    // smallest is the UT.
-    double hUt = std::min(za, zb);
-    double hBs = std::max(za, zb);
-
-    return std::pair<double, double>(hUt, hBs);
-}
-
 int64_t
 ThreeGppPropagationLossModel::DoAssignStreams(int64_t stream)
 {
@@ -590,15 +785,14 @@
 }
 
 double
-ThreeGppRmaPropagationLossModel::GetLossLos(double distance2D,
-                                            double distance3D,
-                                            double hUt,
-                                            double hBs) const
+ThreeGppRmaPropagationLossModel::GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
     NS_ASSERT_MSG(m_frequency <= 30.0e9,
                   "RMa scenario is valid for frequencies between 0.5 and 30 GHz.");
 
+    auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b);
+
     // check if hBS and hUT are within the specified validity range
     if (hUt < 1.0 || hUt > 10.0)
     {
@@ -654,15 +848,14 @@
 }
 
 double
-ThreeGppRmaPropagationLossModel::GetLossNlos(double distance2D,
-                                             double distance3D,
-                                             double hUt,
-                                             double hBs) const
+ThreeGppRmaPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
     NS_ASSERT_MSG(m_frequency <= 30.0e9,
                   "RMa scenario is valid for frequencies between 0.5 and 30 GHz.");
 
+    auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b);
+
     // check if hBs and hUt are within the validity range
     if (hUt < 1.0 || hUt > 10.0)
     {
@@ -699,7 +892,7 @@
                     (43.42 - 3.1 * log10(hBs)) * (log10(distance3D) - 3.0) +
                     20.0 * log10(m_frequency / 1e9) - (3.2 * pow(log10(11.75 * hUt), 2) - 4.97);
 
-    double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos);
+    double loss = std::max(GetLossLos(a, b), plNlos);
 
     NS_LOG_DEBUG("Loss " << loss);
 
@@ -850,13 +1043,12 @@
 }
 
 double
-ThreeGppUmaPropagationLossModel::GetLossLos(double distance2D,
-                                            double distance3D,
-                                            double hUt,
-                                            double hBs) const
+ThreeGppUmaPropagationLossModel::GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b);
+
     // check if hBS and hUT are within the validity range
     if (hUt < 1.5 || hUt > 22.5)
     {
@@ -918,14 +1110,13 @@
 }
 
 double
-ThreeGppUmaPropagationLossModel::GetLossNlos(double distance2D,
-                                             double distance3D,
-                                             double hUt,
-                                             double hBs) const
+ThreeGppUmaPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
-    // check if hBS and hUT are within the vaalidity range
+    auto [distance2D, distance3D, hBs, hUt] = GetBsUtDistancesAndHeights(a, b);
+
+    // check if hBS and hUT are within the validity range
     if (hUt < 1.5 || hUt > 22.5)
     {
         NS_ABORT_MSG_IF(m_enforceRanges, "Uma UT height out of range");
@@ -957,7 +1148,7 @@
     // compute the pathloss
     double plNlos =
         13.54 + 39.08 * log10(distance3D) + 20.0 * log10(m_frequency / 1e9) - 0.6 * (hUt - 1.5);
-    double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos);
+    double loss = std::max(GetLossLos(a, b), plNlos);
     NS_LOG_DEBUG("Loss " << loss);
 
     return loss;
@@ -1074,13 +1265,15 @@
 }
 
 double
-ThreeGppUmiStreetCanyonPropagationLossModel::GetLossLos(double distance2D,
-                                                        double distance3D,
-                                                        double hUt,
-                                                        double hBs) const
+ThreeGppUmiStreetCanyonPropagationLossModel::GetLossLos(Ptr<MobilityModel> a,
+                                                        Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance2D = Calculate2dDistance(a->GetPosition(), b->GetPosition());
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [hBs, hUt] = GetBsUtHeightsUmiStreetCanyon(a->GetPosition().z, b->GetPosition().z);
+
     // check if hBS and hUT are within the validity range
     if (hUt < 1.5 || hUt >= 10.0)
     {
@@ -1135,13 +1328,15 @@
 }
 
 double
-ThreeGppUmiStreetCanyonPropagationLossModel::GetLossNlos(double distance2D,
-                                                         double distance3D,
-                                                         double hUt,
-                                                         double hBs) const
+ThreeGppUmiStreetCanyonPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a,
+                                                         Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance2D = Calculate2dDistance(a->GetPosition(), b->GetPosition());
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [hBs, hUt] = GetBsUtHeightsUmiStreetCanyon(a->GetPosition().z, b->GetPosition().z);
+
     // check if hBS and hUT are within the validity range
     if (hUt < 1.5 || hUt >= 10.0)
     {
@@ -1175,42 +1370,12 @@
     // compute the pathloss
     double plNlos =
         22.4 + 35.3 * log10(distance3D) + 21.3 * log10(m_frequency / 1e9) - 0.3 * (hUt - 1.5);
-    double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos);
+    double loss = std::max(GetLossLos(a, b), plNlos);
     NS_LOG_DEBUG("Loss " << loss);
 
     return loss;
 }
 
-std::pair<double, double>
-ThreeGppUmiStreetCanyonPropagationLossModel::GetUtAndBsHeights(double za, double zb) const
-{
-    NS_LOG_FUNCTION(this);
-    // TR 38.901 specifies hBS = 10 m and 1.5 <= hUT <= 22.5
-    double hBs;
-    double hUt;
-    if (za == 10.0)
-    {
-        // node A is the BS and node B is the UT
-        hBs = za;
-        hUt = zb;
-    }
-    else if (zb == 10.0)
-    {
-        // node B is the BS and node A is the UT
-        hBs = zb;
-        hUt = za;
-    }
-    else
-    {
-        // We cannot know who is the BS and who is the UT, we assume that the
-        // tallest node is the BS and the smallest is the UT
-        hBs = std::max(za, zb);
-        hUt = std::min(za, zb);
-    }
-
-    return std::pair<double, double>(hUt, hBs);
-}
-
 double
 ThreeGppUmiStreetCanyonPropagationLossModel::GetShadowingStd(
     Ptr<MobilityModel> /* a */,
@@ -1295,13 +1460,13 @@
 }
 
 double
-ThreeGppIndoorOfficePropagationLossModel::GetLossLos(double /* distance2D */,
-                                                     double distance3D,
-                                                     double /* hUt */,
-                                                     double /* hBs */) const
+ThreeGppIndoorOfficePropagationLossModel::GetLossLos(Ptr<MobilityModel> a,
+                                                     Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+
     // check if the distance is outside the validity range
     if (distance3D < 1.0 || distance3D > 150.0)
     {
@@ -1319,13 +1484,13 @@
 }
 
 double
-ThreeGppIndoorOfficePropagationLossModel::GetLossNlos(double distance2D,
-                                                      double distance3D,
-                                                      double hUt,
-                                                      double hBs) const
+ThreeGppIndoorOfficePropagationLossModel::GetLossNlos(Ptr<MobilityModel> a,
+                                                      Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+
     // check if the distance is outside the validity range
     if (distance3D < 1.0 || distance3D > 150.0)
     {
@@ -1336,7 +1501,7 @@
 
     // compute the pathloss
     double plNlos = 17.3 + 38.3 * log10(distance3D) + 24.9 * log10(m_frequency / 1e9);
-    double loss = std::max(GetLossLos(distance2D, distance3D, hUt, hBs), plNlos);
+    double loss = std::max(GetLossLos(a, b), plNlos);
 
     NS_LOG_DEBUG("Loss " << loss);
 
@@ -1387,6 +1552,593 @@
     }
     else
     {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return correlationDistance;
+}
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNDenseUrbanPropagationLossModel);
+
+TypeId
+ThreeGppNTNDenseUrbanPropagationLossModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNDenseUrbanPropagationLossModel")
+                            .SetParent<ThreeGppPropagationLossModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNDenseUrbanPropagationLossModel>();
+    return tid;
+}
+
+ThreeGppNTNDenseUrbanPropagationLossModel::ThreeGppNTNDenseUrbanPropagationLossModel()
+    : ThreeGppPropagationLossModel(),
+      m_SFCL_DenseUrban(&SFCL_DenseUrban)
+{
+    NS_LOG_FUNCTION(this);
+    m_channelConditionModel = CreateObject<ThreeGppNTNDenseUrbanChannelConditionModel>();
+}
+
+ThreeGppNTNDenseUrbanPropagationLossModel::~ThreeGppNTNDenseUrbanPropagationLossModel()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+double
+ThreeGppNTNDenseUrbanPropagationLossModel::GetO2iDistance2dIn() const
+{
+    abort();
+}
+
+double
+ThreeGppNTNDenseUrbanPropagationLossModel::GetLossLos(Ptr<MobilityModel> a,
+                                                      Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNDenseUrbanPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a,
+                                                       Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Clutter Loss
+    loss += ComputeClutterLoss(m_frequency, m_SFCL_DenseUrban, elevAngleQuantized);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNDenseUrbanPropagationLossModel::GetShadowingStd(
+    Ptr<MobilityModel> a,
+    Ptr<MobilityModel> b,
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double shadowingStd;
+
+    std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka";
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // Assign Shadowing Standard Deviation according to table 6.6.2-1
+    if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_DenseUrban).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF];
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return shadowingStd;
+}
+
+double
+ThreeGppNTNDenseUrbanPropagationLossModel::GetShadowingCorrelationDistance(
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double correlationDistance;
+
+    // See 3GPP TR 38.811, Table 6.7.2-1a/b and Table 6.7.2-2a/b
+    if (cond == ChannelCondition::LosConditionValue::LOS)
+    {
+        correlationDistance = 37;
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS)
+    {
+        correlationDistance = 50;
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return correlationDistance;
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNUrbanPropagationLossModel);
+
+TypeId
+ThreeGppNTNUrbanPropagationLossModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNUrbanPropagationLossModel")
+                            .SetParent<ThreeGppPropagationLossModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNUrbanPropagationLossModel>();
+    return tid;
+}
+
+ThreeGppNTNUrbanPropagationLossModel::ThreeGppNTNUrbanPropagationLossModel()
+    : ThreeGppPropagationLossModel(),
+      m_SFCL_Urban(&SFCL_Urban)
+{
+    NS_LOG_FUNCTION(this);
+    m_channelConditionModel = CreateObject<ThreeGppNTNUrbanChannelConditionModel>();
+}
+
+ThreeGppNTNUrbanPropagationLossModel::~ThreeGppNTNUrbanPropagationLossModel()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+double
+ThreeGppNTNUrbanPropagationLossModel::GetO2iDistance2dIn() const
+{
+    abort();
+}
+
+double
+ThreeGppNTNUrbanPropagationLossModel::GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNUrbanPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Clutter Loss
+    loss += ComputeClutterLoss(m_frequency, m_SFCL_Urban, elevAngleQuantized);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNUrbanPropagationLossModel::GetShadowingStd(
+    Ptr<MobilityModel> a,
+    Ptr<MobilityModel> b,
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double shadowingStd;
+
+    std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka";
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // Assign Shadowing Standard Deviation according to table 6.6.2-1
+    if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_Urban).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF];
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return shadowingStd;
+}
+
+double
+ThreeGppNTNUrbanPropagationLossModel::GetShadowingCorrelationDistance(
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double correlationDistance;
+
+    // See 3GPP TR 38.811, Table 6.7.2-3a/b and Table 6.7.2-3a/b
+    if (cond == ChannelCondition::LosConditionValue::LOS)
+    {
+        correlationDistance = 37;
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS)
+    {
+        correlationDistance = 50;
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return correlationDistance;
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNSuburbanPropagationLossModel);
+
+TypeId
+ThreeGppNTNSuburbanPropagationLossModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNSuburbanPropagationLossModel")
+                            .SetParent<ThreeGppPropagationLossModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNSuburbanPropagationLossModel>();
+    return tid;
+}
+
+ThreeGppNTNSuburbanPropagationLossModel::ThreeGppNTNSuburbanPropagationLossModel()
+    : ThreeGppPropagationLossModel(),
+      m_SFCL_SuburbanRural(&SFCL_SuburbanRural)
+{
+    NS_LOG_FUNCTION(this);
+    m_channelConditionModel = CreateObject<ThreeGppNTNSuburbanChannelConditionModel>();
+}
+
+ThreeGppNTNSuburbanPropagationLossModel::~ThreeGppNTNSuburbanPropagationLossModel()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+double
+ThreeGppNTNSuburbanPropagationLossModel::GetO2iDistance2dIn() const
+{
+    abort();
+}
+
+double
+ThreeGppNTNSuburbanPropagationLossModel::GetLossLos(Ptr<MobilityModel> a,
+                                                    Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+
+    return loss;
+}
+
+double
+ThreeGppNTNSuburbanPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a,
+                                                     Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Clutter Loss
+    loss += ComputeClutterLoss(m_frequency, m_SFCL_SuburbanRural, elevAngleQuantized);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNSuburbanPropagationLossModel::GetShadowingStd(
+    Ptr<MobilityModel> a,
+    Ptr<MobilityModel> b,
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double shadowingStd;
+
+    std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka";
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // Assign Shadowing Standard Deviation according to table 6.6.2-1
+    if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF];
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return shadowingStd;
+}
+
+double
+ThreeGppNTNSuburbanPropagationLossModel::GetShadowingCorrelationDistance(
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double correlationDistance;
+
+    // See 3GPP TR 38.811, Table 6.7.2-5a/b and Table 6.7.2-6a/b
+    if (cond == ChannelCondition::LosConditionValue::LOS)
+    {
+        correlationDistance = 37;
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS)
+    {
+        correlationDistance = 50;
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return correlationDistance;
+}
+
+// ------------------------------------------------------------------------- //
+
+NS_OBJECT_ENSURE_REGISTERED(ThreeGppNTNRuralPropagationLossModel);
+
+TypeId
+ThreeGppNTNRuralPropagationLossModel::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::ThreeGppNTNRuralPropagationLossModel")
+                            .SetParent<ThreeGppPropagationLossModel>()
+                            .SetGroupName("Propagation")
+                            .AddConstructor<ThreeGppNTNRuralPropagationLossModel>();
+    return tid;
+}
+
+ThreeGppNTNRuralPropagationLossModel::ThreeGppNTNRuralPropagationLossModel()
+    : ThreeGppPropagationLossModel(),
+      m_SFCL_SuburbanRural(&SFCL_SuburbanRural)
+{
+    NS_LOG_FUNCTION(this);
+    m_channelConditionModel = CreateObject<ThreeGppNTNRuralChannelConditionModel>();
+}
+
+ThreeGppNTNRuralPropagationLossModel::~ThreeGppNTNRuralPropagationLossModel()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+double
+ThreeGppNTNRuralPropagationLossModel::GetO2iDistance2dIn() const
+{
+    abort();
+}
+
+double
+ThreeGppNTNRuralPropagationLossModel::GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNRuralPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT_MSG(m_frequency <= 100.0e9,
+                  "NTN communications are valid for frequencies between 0.5 and 100 GHz.");
+
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // compute the pathloss (see 3GPP TR 38.811, Table 6.6.2)
+    double loss = ComputeNtnPathloss(m_frequency, distance3D);
+
+    // Apply Clutter Loss
+    loss += ComputeClutterLoss(m_frequency, m_SFCL_SuburbanRural, elevAngleQuantized);
+
+    // Apply Atmospheric Absorption Loss 3GPP 38.811 6.6.4
+    loss += ComputeAtmosphericAbsorptionLoss(m_frequency, elevAngle);
+
+    // Apply Ionospheric plus Tropospheric Scintillation Loss
+    loss += ComputeIonosphericPlusTroposphericScintillationLoss(m_frequency, elevAngleQuantized);
+
+    NS_LOG_DEBUG("Loss " << loss);
+    return loss;
+}
+
+double
+ThreeGppNTNRuralPropagationLossModel::GetShadowingStd(
+    Ptr<MobilityModel> a,
+    Ptr<MobilityModel> b,
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double shadowingStd;
+
+    std::string freqBand = (m_frequency < 13.0e9) ? "S" : "Ka";
+    auto [elevAngle, elevAngleQuantized] =
+        ThreeGppChannelConditionModel::GetQuantizedElevationAngle(a, b);
+
+    // Assign Shadowing Standard Deviation according to table 6.6.2-1
+    if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::LOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_LOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "S")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::S_NLOS_sigF];
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS && freqBand == "Ka")
+    {
+        shadowingStd = (*m_SFCL_SuburbanRural).at(elevAngleQuantized)[SFCL_params::Ka_NLOS_sigF];
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown channel condition");
+    }
+
+    return shadowingStd;
+}
+
+double
+ThreeGppNTNRuralPropagationLossModel::GetShadowingCorrelationDistance(
+    ChannelCondition::LosConditionValue cond) const
+{
+    NS_LOG_FUNCTION(this);
+    double correlationDistance;
+
+    // See 3GPP TR 38.811, Table 6.7.2-7a/b and Table 6.7.2-8a/b
+    if (cond == ChannelCondition::LosConditionValue::LOS)
+    {
+        correlationDistance = 37;
+    }
+    else if (cond == ChannelCondition::LosConditionValue::NLOS)
+    {
+        correlationDistance = 120;
+    }
+    else
+    {
         NS_FATAL_ERROR("Unknown channel condition");
     }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/three-gpp-propagation-loss-model.h ns-3.42/src/propagation/model/three-gpp-propagation-loss-model.h
--- ns-3.41/src/propagation/model/three-gpp-propagation-loss-model.h	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/three-gpp-propagation-loss-model.h	2024-05-29 15:29:47.160073800 -0700
@@ -105,31 +105,29 @@
     /**
      * \brief Computes the pathloss between a and b
      * \param cond the channel condition
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLoss(Ptr<ChannelCondition> cond,
-                   double distance2D,
-                   double distance3D,
-                   double hUt,
-                   double hBs) const;
+    double GetLoss(Ptr<ChannelCondition> cond, Ptr<MobilityModel> a, Ptr<MobilityModel> b) const;
 
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
+     * \return pathloss value in dB
+     */
+    virtual double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const = 0;
+
+    /**
+     * \brief Computes the pathloss between a and b considering that the line of
+     *        sight is obstructed
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    virtual double GetLossLos(double distance2D,
-                              double distance3D,
-                              double hUt,
-                              double hBs) const = 0;
+    virtual double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const = 0;
 
     /**
      * \brief Returns the minimum of the two independently generated distances
@@ -197,39 +195,13 @@
 
     /**
      * \brief Computes the pathloss between a and b considering that the line of
-     *        sight is obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
-     * \return pathloss value in dB
-     */
-    virtual double GetLossNlos(double distance2D,
-                               double distance3D,
-                               double hUt,
-                               double hBs) const = 0;
-
-    /**
-     * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed by a vehicle. By default it raises an error to
      *        avoid misuse.
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    virtual double GetLossNlosv(double distance2D, double distance3D, double hUt, double hBs) const;
-
-    /**
-     * \brief Determines hUT and hBS. The default implementation assumes that
-     *        the tallest node is the BS and the smallest is the UT. The derived classes
-     * can change the default behavior by overriding this method.
-     * \param za the height of the first node in meters
-     * \param zb the height of the second node in meters
-     * \return std::pair of heights in meters, the first element is hUt and the second is hBs
-     */
-    virtual std::pair<double, double> GetUtAndBsHeights(double za, double zb) const;
+    virtual double GetLossNlosv(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const;
 
     /**
      * \brief Retrieves the shadowing value by looking at m_shadowingMap.
@@ -374,13 +346,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the minimum of the two independently generated distances
@@ -407,13 +377,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the shadow fading standard deviation
@@ -491,13 +459,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the minimum of the two independently generated distances
@@ -516,13 +482,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed.
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the shadow fading standard deviation
@@ -590,13 +554,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the minimum of the two independently generated distances
@@ -615,13 +577,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed.
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the shadow fading standard deviation
@@ -649,14 +609,6 @@
      * \return the breakpoint distance in meters
      */
     double GetBpDistance(double hUt, double hBs, double distance2D) const;
-
-    /**
-     * \brief Determines hUT and hBS. Overrides the default implementation.
-     * \param za the height of the first node in meters
-     * \param zb the height of the second node in meters
-     * \return std::pair, the first element is hUt and the second is hBs
-     */
-    std::pair<double, double> GetUtAndBsHeights(double za, double zb) const override;
 };
 
 /**
@@ -694,13 +646,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the minimum of the two independently generated distances
@@ -719,13 +669,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a tx mobility model
+     * \param b rx mobility model
      * \return pathloss value in dB
      */
-    double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the shadow fading standard deviation
@@ -746,6 +694,260 @@
     double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override;
 };
 
+/**
+ * \ingroup propagation
+ *
+ * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ????
+ *        for the NTN Dense Urban scenario.
+ */
+class ThreeGppNTNDenseUrbanPropagationLossModel : public ThreeGppPropagationLossModel
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor
+     */
+    ThreeGppNTNDenseUrbanPropagationLossModel();
+
+    /**
+     * Destructor
+     */
+    ~ThreeGppNTNDenseUrbanPropagationLossModel() override;
+
+    /**
+     * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn
+     *  Does nothing in NTN scenarios.
+     */
+    double GetO2iDistance2dIn() const override;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     */
+    ThreeGppNTNDenseUrbanPropagationLossModel(const ThreeGppNTNDenseUrbanPropagationLossModel&) =
+        delete;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     * \returns the ThreeGppNTNDenseUrbanPropagationLossModel instance
+     */
+    ThreeGppNTNDenseUrbanPropagationLossModel& operator=(
+        const ThreeGppNTNDenseUrbanPropagationLossModel&) = delete;
+
+  private:
+    // Inherited
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetShadowingStd(Ptr<MobilityModel> a,
+                           Ptr<MobilityModel> b,
+                           ChannelCondition::LosConditionValue cond) const override;
+    double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override;
+
+    /**
+     * \brief The nested map containing the Shadow Fading and
+     *        Clutter Loss values for the NTN Dense Urban scenario
+     */
+    const std::map<int, std::vector<float>>* m_SFCL_DenseUrban;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ????
+ *        for the NTN Urban scenario.
+ */
+class ThreeGppNTNUrbanPropagationLossModel : public ThreeGppPropagationLossModel
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor
+     */
+    ThreeGppNTNUrbanPropagationLossModel();
+
+    /**
+     * Destructor
+     */
+    ~ThreeGppNTNUrbanPropagationLossModel() override;
+
+    /**
+     * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn
+     *  Does nothing in NTN scenarios.
+     */
+    double GetO2iDistance2dIn() const override;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     */
+    ThreeGppNTNUrbanPropagationLossModel(const ThreeGppNTNUrbanPropagationLossModel&) = delete;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     * \returns the ThreeGppNTNUrbanPropagationLossModel instance
+     */
+    ThreeGppNTNUrbanPropagationLossModel& operator=(const ThreeGppNTNUrbanPropagationLossModel&) =
+        delete;
+
+  private:
+    // Inherited
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetShadowingStd(Ptr<MobilityModel> a,
+                           Ptr<MobilityModel> b,
+                           ChannelCondition::LosConditionValue cond) const override;
+    double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override;
+
+    /**
+     * \brief The nested map containing the Shadow Fading and
+     *        Clutter Loss values for the NTN Urban scenario
+     */
+    const std::map<int, std::vector<float>>* m_SFCL_Urban;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ????
+ *        for the NTN Suburban scenario.
+ */
+class ThreeGppNTNSuburbanPropagationLossModel : public ThreeGppPropagationLossModel
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor
+     */
+    ThreeGppNTNSuburbanPropagationLossModel();
+
+    /**
+     * Destructor
+     */
+    ~ThreeGppNTNSuburbanPropagationLossModel() override;
+
+    /**
+     * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn
+     *  Does nothing in NTN scenarios.
+     */
+    double GetO2iDistance2dIn() const override;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     */
+    ThreeGppNTNSuburbanPropagationLossModel(const ThreeGppNTNSuburbanPropagationLossModel&) =
+        delete;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     * \returns the ThreeGppNTNSuburbanPropagationLossModel instance
+     */
+    ThreeGppNTNSuburbanPropagationLossModel& operator=(
+        const ThreeGppNTNSuburbanPropagationLossModel&) = delete;
+
+  private:
+    // Inherited
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetShadowingStd(Ptr<MobilityModel> a,
+                           Ptr<MobilityModel> b,
+                           ChannelCondition::LosConditionValue cond) const override;
+    double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override;
+
+    /**
+     * \brief The nested map containing the Shadow Fading and
+     *        Clutter Loss values for the NTN Suburban and Rural scenario
+     */
+    const std::map<int, std::vector<float>>* m_SFCL_SuburbanRural;
+};
+
+/**
+ * \ingroup propagation
+ *
+ * \brief Implements the pathloss model defined in 3GPP TR 38.811, Table ????
+ *        for the NTN Rural scenario.
+ */
+class ThreeGppNTNRuralPropagationLossModel : public ThreeGppPropagationLossModel
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * Constructor
+     */
+    ThreeGppNTNRuralPropagationLossModel();
+
+    /**
+     * Destructor
+     */
+    ~ThreeGppNTNRuralPropagationLossModel() override;
+
+    /**
+     * \copydoc ThreeGppPropagationLossModel::GetO2iDistance2dIn
+     *  Does nothing in NTN scenarios.
+     */
+    double GetO2iDistance2dIn() const override;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     */
+    ThreeGppNTNRuralPropagationLossModel(const ThreeGppNTNRuralPropagationLossModel&) = delete;
+
+    /**
+     * \brief Copy constructor
+     *
+     * Deleted in base class
+     * \returns the ThreeGppNTNRuralPropagationLossModel instance
+     */
+    ThreeGppNTNRuralPropagationLossModel& operator=(const ThreeGppNTNRuralPropagationLossModel&) =
+        delete;
+
+  private:
+    // Inherited
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
+    double GetShadowingStd(Ptr<MobilityModel> a,
+                           Ptr<MobilityModel> b,
+                           ChannelCondition::LosConditionValue cond) const override;
+    double GetShadowingCorrelationDistance(ChannelCondition::LosConditionValue cond) const override;
+
+    /**
+     * \brief The nested map containing the Shadow Fading and
+     *        Clutter Loss values for the NTN Suburban and Rural scenario
+     */
+    const std::map<int, std::vector<float>>* m_SFCL_SuburbanRural;
+};
+
 } // namespace ns3
 
 #endif /* THREE_GPP_PROPAGATION_LOSS_MODEL_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc ns-3.42/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc
--- ns-3.41/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/three-gpp-v2v-propagation-loss-model.cc	2024-05-29 15:29:47.160073800 -0700
@@ -66,13 +66,12 @@
 }
 
 double
-ThreeGppV2vUrbanPropagationLossModel::GetLossLos(double /* distance2D */,
-                                                 double distance3D,
-                                                 double /* hUt */,
-                                                 double /* hBs */) const
+ThreeGppV2vUrbanPropagationLossModel::GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+
     // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1)
     double loss = 38.77 + 16.7 * log10(distance3D) + 18.2 * log10(m_frequency / 1e9);
 
@@ -88,26 +87,25 @@
 }
 
 double
-ThreeGppV2vUrbanPropagationLossModel::GetLossNlosv(double distance2D,
-                                                   double distance3D,
-                                                   double hUt,
-                                                   double hBs) const
+ThreeGppV2vUrbanPropagationLossModel::GetLossNlosv(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
     // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1)
-    double loss =
-        GetLossLos(distance2D, distance3D, hUt, hBs) + GetAdditionalNlosvLoss(distance3D, hUt, hBs);
+    double loss = GetLossLos(a, b) + GetAdditionalNlosvLoss(a, b);
 
     return loss;
 }
 
 double
-ThreeGppV2vUrbanPropagationLossModel::GetAdditionalNlosvLoss(double distance3D,
-                                                             double hUt,
-                                                             double hBs) const
+ThreeGppV2vUrbanPropagationLossModel::GetAdditionalNlosvLoss(Ptr<MobilityModel> a,
+                                                             Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+    double hBs = std::max(a->GetPosition().z, b->GetPosition().z);
+    double hUt = std::min(a->GetPosition().z, b->GetPosition().z);
+
     // From TR 37.885 v15.2.0
     // When a V2V link is in NLOSv, additional vehicle blockage loss is
     // added as follows:
@@ -166,13 +164,12 @@
 }
 
 double
-ThreeGppV2vUrbanPropagationLossModel::GetLossNlos(double /* distance2D */,
-                                                  double distance3D,
-                                                  double /* hUt */,
-                                                  double /* hBs */) const
+ThreeGppV2vUrbanPropagationLossModel::GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+
     double loss = 36.85 + 30 * log10(distance3D) + 18.9 * log10(m_frequency / 1e9);
 
     return loss;
@@ -266,13 +263,12 @@
 }
 
 double
-ThreeGppV2vHighwayPropagationLossModel::GetLossLos(double /* distance2D */,
-                                                   double distance3D,
-                                                   double /* hUt */,
-                                                   double /* hBs */) const
+ThreeGppV2vHighwayPropagationLossModel::GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const
 {
     NS_LOG_FUNCTION(this);
 
+    double distance3D = CalculateDistance(a->GetPosition(), b->GetPosition());
+
     // compute the pathloss (see 3GPP TR 37.885, Table 6.2.1-1)
     double loss = 32.4 + 20 * log10(distance3D) + 20 * log10(m_frequency / 1e9);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/model/three-gpp-v2v-propagation-loss-model.h ns-3.42/src/propagation/model/three-gpp-v2v-propagation-loss-model.h
--- ns-3.41/src/propagation/model/three-gpp-v2v-propagation-loss-model.h	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/model/three-gpp-v2v-propagation-loss-model.h	2024-05-29 15:29:47.160073800 -0700
@@ -21,6 +21,9 @@
 
 #include "three-gpp-propagation-loss-model.h"
 
+#include "ns3/deprecated.h"
+#include <ns3/mobility-model.h>
+
 namespace ns3
 {
 
@@ -49,7 +52,6 @@
      */
     ~ThreeGppV2vUrbanPropagationLossModel() override;
 
-    // Delete copy constructor and assignment operator to avoid misuse
     ThreeGppV2vUrbanPropagationLossModel(const ThreeGppV2vUrbanPropagationLossModel&) = delete;
     ThreeGppV2vUrbanPropagationLossModel& operator=(const ThreeGppV2vUrbanPropagationLossModel&) =
         delete;
@@ -58,13 +60,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a mobility model of one of the two communicating nodes
+     * \param b mobility model of one of the two communicating nodes
      * \return pathloss value in dB
      */
-    double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Returns the minimum of the two independently generated distances
@@ -86,41 +86,33 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed by a vehicle
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a mobility model of one of the two communicating nodes
+     * \param b mobility model of one of the two communicating nodes
      * \return pathloss value in dB
      */
-    double GetLossNlosv(double distance2D,
-                        double distance3D,
-                        double hUt,
-                        double hBs) const override;
+    double GetLossNlosv(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is obstructed by a building
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a mobility model of one of the two communicating nodes
+     * \param b mobility model of one of the two communicating nodes
      * \return pathloss value in dB
      */
-    double GetLossNlos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossNlos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 
     /**
      * \brief Computes the additional loss due to an obstruction caused by a vehicle
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a mobility model of one of the two communicating nodes
+     * \param b mobility model of one of the two communicating nodes
      * \return pathloss value in dB
      */
-    double GetAdditionalNlosvLoss(double distance3D, double hUt, double hBs) const;
+    double GetAdditionalNlosvLoss(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const;
 
     /**
      * \brief Returns the shadow fading standard deviation
-     * \param a tx mobility model
-     * \param b rx mobility model
+     * \param a mobility model of one of the two communicating nodes
+     * \param b mobility model of one of the two communicating nodes
      * \param cond the LOS/NLOS channel condition
      * \return shadowing std in dB
      */
@@ -171,13 +163,11 @@
     /**
      * \brief Computes the pathloss between a and b considering that the line of
      *        sight is not obstructed
-     * \param distance2D the 2D distance between tx and rx in meters
-     * \param distance3D the 3D distance between tx and rx in meters
-     * \param hUt the height of the UT in meters
-     * \param hBs the height of the BS in meters
+     * \param a mobility model of one of the two communicating nodes
+     * \param b mobility model of one of the two communicating nodes
      * \return pathloss value in dB
      */
-    double GetLossLos(double distance2D, double distance3D, double hUt, double hBs) const override;
+    double GetLossLos(Ptr<MobilityModel> a, Ptr<MobilityModel> b) const override;
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/channel-condition-model-test-suite.cc ns-3.42/src/propagation/test/channel-condition-model-test-suite.cc
--- ns-3.41/src/propagation/test/channel-condition-model-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/channel-condition-model-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -289,9 +289,9 @@
 };
 
 ChannelConditionModelsTestSuite::ChannelConditionModelsTestSuite()
-    : TestSuite("propagation-channel-condition-model", UNIT)
+    : TestSuite("propagation-channel-condition-model", Type::UNIT)
 {
-    AddTestCase(new ThreeGppChannelConditionModelTestCase, TestCase::QUICK);
+    AddTestCase(new ThreeGppChannelConditionModelTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/itu-r-1411-los-test-suite.cc ns-3.42/src/propagation/test/itu-r-1411-los-test-suite.cc
--- ns-3.41/src/propagation/test/itu-r-1411-los-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/itu-r-1411-los-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -129,7 +129,7 @@
 };
 
 ItuR1411LosPropagationLossModelTestSuite::ItuR1411LosPropagationLossModelTestSuite()
-    : TestSuite("itu-r-1411-los", SYSTEM)
+    : TestSuite("itu-r-1411-los", Type::SYSTEM)
 {
     LogComponentEnable("ItuR1411LosPropagationLossModelTest", LOG_LEVEL_ALL);
 
@@ -140,14 +140,14 @@
                                                             1,
                                                             81.005,
                                                             "freq=2114MHz, dist=100m"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ItuR1411LosPropagationLossModelTestCase(1999e6,
                                                             200,
                                                             30,
                                                             1,
                                                             87.060,
                                                             "freq=1999MHz, dist=200m"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/itu-r-1411-nlos-over-rooftop-test-suite.cc ns-3.42/src/propagation/test/itu-r-1411-nlos-over-rooftop-test-suite.cc
--- ns-3.41/src/propagation/test/itu-r-1411-nlos-over-rooftop-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/itu-r-1411-nlos-over-rooftop-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -144,7 +144,7 @@
 
 ItuR1411NlosOverRooftopPropagationLossModelTestSuite::
     ItuR1411NlosOverRooftopPropagationLossModelTestSuite()
-    : TestSuite("itu-r-1411-nlos-over-rooftop", SYSTEM)
+    : TestSuite("itu-r-1411-nlos-over-rooftop", Type::SYSTEM)
 {
     LogComponentEnable("ItuR1411NlosOverRooftopPropagationLossModelTest", LOG_LEVEL_ALL);
 
@@ -158,7 +158,7 @@
                     LargeCity,
                     143.68,
                     "f=2114Mhz, dist=900, urban large city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ItuR1411NlosOverRooftopPropagationLossModelTestCase(
                     1.865e9,
                     500,
@@ -168,7 +168,7 @@
                     LargeCity,
                     132.84,
                     "f=2114Mhz, dist=900, urban large city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/kun-2600-mhz-test-suite.cc ns-3.42/src/propagation/test/kun-2600-mhz-test-suite.cc
--- ns-3.41/src/propagation/test/kun-2600-mhz-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/kun-2600-mhz-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -123,12 +123,12 @@
 };
 
 Kun2600MhzPropagationLossModelTestSuite::Kun2600MhzPropagationLossModelTestSuite()
-    : TestSuite("kun-2600-mhz", SYSTEM)
+    : TestSuite("kun-2600-mhz", Type::SYSTEM)
 {
     LogComponentEnable("Kun2600MhzPropagationLossModelTest", LOG_LEVEL_ALL);
 
     AddTestCase(new Kun2600MhzPropagationLossModelTestCase(2000, 30, 1, 121.83, "dist=2000m"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/okumura-hata-test-suite.cc ns-3.42/src/propagation/test/okumura-hata-test-suite.cc
--- ns-3.41/src/propagation/test/okumura-hata-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/okumura-hata-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -146,7 +146,7 @@
 };
 
 OkumuraHataPropagationLossModelTestSuite::OkumuraHataPropagationLossModelTestSuite()
-    : TestSuite("okumura-hata", SYSTEM)
+    : TestSuite("okumura-hata", Type::SYSTEM)
 {
     LogComponentEnable("OkumuraHataPropagationLossModelTest", LOG_LEVEL_ALL);
     // reference values obtained with the octave scripts in src/propagation/test/reference/
@@ -160,7 +160,7 @@
                                                             LargeCity,
                                                             137.93,
                                                             "original OH Urban Large city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OkumuraHataPropagationLossModelTestCase(freq,
                                                             2000,
                                                             30,
@@ -169,7 +169,7 @@
                                                             SmallCity,
                                                             137.88,
                                                             "original OH Urban small city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OkumuraHataPropagationLossModelTestCase(freq,
                                                             2000,
                                                             30,
@@ -178,7 +178,7 @@
                                                             LargeCity,
                                                             128.03,
                                                             "original OH SubUrban"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new OkumuraHataPropagationLossModelTestCase(freq,
                                                             2000,
                                                             30,
@@ -187,7 +187,7 @@
                                                             LargeCity,
                                                             110.21,
                                                             "original OH OpenAreas"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     freq = 2.1140e9; // this will use the extended COST231 OH model
     AddTestCase(new OkumuraHataPropagationLossModelTestCase(freq,
@@ -198,7 +198,7 @@
                                                             LargeCity,
                                                             148.55,
                                                             "COST231 OH Urban Large city"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new OkumuraHataPropagationLossModelTestCase(freq,
                                                     2000,
@@ -208,7 +208,7 @@
                                                     SmallCity,
                                                     150.64,
                                                     "COST231 OH Urban small city and suburban"),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/probabilistic-v2v-channel-condition-model-test.cc ns-3.42/src/propagation/test/probabilistic-v2v-channel-condition-model-test.cc
--- ns-3.41/src/propagation/test/probabilistic-v2v-channel-condition-model-test.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/probabilistic-v2v-channel-condition-model-test.cc	2024-05-29 15:29:47.160073800 -0700
@@ -519,14 +519,14 @@
 };
 
 ProbabilisticV2vChCondModelsTestSuite::ProbabilisticV2vChCondModelsTestSuite()
-    : TestSuite("probabilistic-v2v-channel-condition-model", SYSTEM)
+    : TestSuite("probabilistic-v2v-channel-condition-model", Type::SYSTEM)
 {
     AddTestCase(new V2vUrbanProbChCondModelTestCase,
-                TestCase::QUICK); // test for a fully probabilistic model (NLOS vs LOS vs NLOSv), in
-                                  // V2V urban scenario
+                TestCase::Duration::QUICK); // test for a fully probabilistic model (NLOS vs LOS
+                                            // vs NLOSv), in V2V urban scenario
     AddTestCase(new V2vHighwayProbChCondModelTestCase,
-                TestCase::QUICK); // test for a fully probabilistic model (NLOS vs LOS vs NLOSv), in
-                                  // V2V highway scenario*/
+                TestCase::Duration::QUICK); // test for a fully probabilistic model (NLOS vs LOS
+                                            // vs NLOSv), in V2V highway scenario*/
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/propagation-loss-model-test-suite.cc ns-3.42/src/propagation/test/propagation-loss-model-test-suite.cc
--- ns-3.41/src/propagation/test/propagation-loss-model-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/propagation-loss-model-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -508,13 +508,13 @@
 };
 
 PropagationLossModelsTestSuite::PropagationLossModelsTestSuite()
-    : TestSuite("propagation-loss-model", UNIT)
+    : TestSuite("propagation-loss-model", Type::UNIT)
 {
-    AddTestCase(new FriisPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new TwoRayGroundPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new LogDistancePropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new MatrixPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new RangePropagationLossModelTestCase, TestCase::QUICK);
+    AddTestCase(new FriisPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new TwoRayGroundPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new LogDistancePropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new MatrixPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new RangePropagationLossModelTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc ns-3.42/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc
--- ns-3.41/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/propagation/test/three-gpp-ntn-propagation-loss-model-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2023 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ns3/abort.h"
+#include "ns3/boolean.h"
+#include "ns3/channel-condition-model.h"
+#include "ns3/config.h"
+#include "ns3/constant-position-mobility-model.h"
+#include "ns3/constant-velocity-mobility-model.h"
+#include "ns3/double.h"
+#include "ns3/geocentric-constant-position-mobility-model.h"
+#include "ns3/log.h"
+#include "ns3/mobility-helper.h"
+#include "ns3/simulator.h"
+#include "ns3/test.h"
+#include "ns3/three-gpp-propagation-loss-model.h"
+#include "ns3/three-gpp-v2v-propagation-loss-model.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("ThreeGppNTNPropagationLossModelsTest");
+
+/**
+ * \ingroup propagation-tests
+ *
+ * Test case for the ThreeGppNTNPropagationLossModel classes.
+ * It computes the path loss between two nodes and compares it with the value
+ * obtained using the results provided in 3GPP TR 38.821.
+ */
+class ThreeGppNTNPropagationLossModelTestCase : public TestCase
+{
+  public:
+    ThreeGppNTNPropagationLossModelTestCase();
+
+    /**
+     * Description of a single test point
+     */
+    struct TestPoint
+    {
+        /**
+         * @brief Constructor
+         *
+         * @param distance  2D distance between the test nodes
+         * @param isLos     whether to compute the path loss for a channel LOS condition
+         * @param frequency carrier frequency in Hz
+         * @param pwrRxDbm  expected received power in dBm
+         * @param lossModel the propagation loss model to test
+         */
+        TestPoint(double distance,
+                  bool isLos,
+                  double frequency,
+                  double pwrRxDbm,
+                  Ptr<ThreeGppPropagationLossModel> lossModel)
+            : m_distance(distance),
+              m_isLos(isLos),
+              m_frequency(frequency),
+              m_pwrRxDbm(pwrRxDbm),
+              m_propagationLossModel(lossModel)
+        {
+        }
+
+        double m_distance;  //!< 2D distance between test nodes, in meters
+        bool m_isLos;       //!< if true LOS, if false NLOS
+        double m_frequency; //!< carrier frequency in Hz
+        double m_pwrRxDbm;  //!< received power in dBm
+        Ptr<ThreeGppPropagationLossModel> m_propagationLossModel; //!< the path loss model to test
+    };
+
+  private:
+    /**
+     * Build the simulation scenario and run the tests
+     */
+    void DoRun() override;
+
+    /**
+     * Test the channel gain for a specific parameter configuration,
+     * by comparing the antenna gain obtained using CircularApertureAntennaModel::GetGainDb
+     * and the one of manually computed test instances.
+     *
+     * @param testPoint the parameter configuration to be tested
+     */
+    void TestChannelGain(TestPoint testPoint);
+};
+
+ThreeGppNTNPropagationLossModelTestCase::ThreeGppNTNPropagationLossModelTestCase()
+    : TestCase("Creating ThreeGppNTNPropagationLossModelTestCase")
+
+{
+}
+
+void
+ThreeGppNTNPropagationLossModelTestCase::DoRun()
+{
+    // Create the PLMs and disable shadowing to obtain deterministic results
+    Ptr<ThreeGppNTNDenseUrbanPropagationLossModel> denseUrbanModel =
+        CreateObject<ThreeGppNTNDenseUrbanPropagationLossModel>();
+    denseUrbanModel->SetAttribute("ShadowingEnabled", BooleanValue(false));
+    Ptr<ThreeGppNTNUrbanPropagationLossModel> urbanModel =
+        CreateObject<ThreeGppNTNUrbanPropagationLossModel>();
+    urbanModel->SetAttribute("ShadowingEnabled", BooleanValue(false));
+    Ptr<ThreeGppNTNSuburbanPropagationLossModel> suburbanModel =
+        CreateObject<ThreeGppNTNSuburbanPropagationLossModel>();
+    suburbanModel->SetAttribute("ShadowingEnabled", BooleanValue(false));
+    Ptr<ThreeGppNTNRuralPropagationLossModel> ruralModel =
+        CreateObject<ThreeGppNTNRuralPropagationLossModel>();
+    ruralModel->SetAttribute("ShadowingEnabled", BooleanValue(false));
+
+    //  Vector of test points
+    std::vector<TestPoint> testPoints = {
+        // LOS, test points are identical for all path loss models, since the LOS path loss
+        // is independent from the specific class.
+        // Dense-Urban LOS
+        {35786000, true, 20.0e9, -209.915, denseUrbanModel},
+        {35786000, true, 30.0e9, -213.437, denseUrbanModel},
+        {35786000, true, 2.0e9, -191.744, denseUrbanModel},
+        {600000, true, 20.0e9, -174.404, denseUrbanModel},
+        {600000, true, 30.0e9, -177.925, denseUrbanModel},
+        {600000, true, 2.0e9, -156.233, denseUrbanModel},
+        {1200000, true, 20.0e9, -180.424, denseUrbanModel},
+        {1200000, true, 30.0e9, -183.946, denseUrbanModel},
+        {1200000, true, 2.0e9, -162.253, denseUrbanModel},
+        // Urban LOS
+        {35786000, true, 20.0e9, -209.915, urbanModel},
+        {35786000, true, 30.0e9, -213.437, urbanModel},
+        {35786000, true, 2.0e9, -191.744, urbanModel},
+        {600000, true, 20.0e9, -174.404, urbanModel},
+        {600000, true, 30.0e9, -177.925, urbanModel},
+        {600000, true, 2.0e9, -156.233, urbanModel},
+        {1200000, true, 20.0e9, -180.424, urbanModel},
+        {1200000, true, 30.0e9, -183.946, urbanModel},
+        {1200000, true, 2.0e9, -162.253, urbanModel},
+        // Suburban LOS
+        {35786000, true, 20.0e9, -209.915, suburbanModel},
+        {35786000, true, 30.0e9, -213.437, suburbanModel},
+        {35786000, true, 2.0e9, -191.744, suburbanModel},
+        {600000, true, 20.0e9, -174.404, suburbanModel},
+        {600000, true, 30.0e9, -177.925, suburbanModel},
+        {600000, true, 2.0e9, -156.233, suburbanModel},
+        {1200000, true, 20.0e9, -180.424, suburbanModel},
+        {1200000, true, 30.0e9, -183.946, suburbanModel},
+        {1200000, true, 2.0e9, -162.253, suburbanModel},
+        // Rural LOS
+        {35786000, true, 20.0e9, -209.915, ruralModel},
+        {35786000, true, 30.0e9, -213.437, ruralModel},
+        {35786000, true, 2.0e9, -191.744, ruralModel},
+        {600000, true, 20.0e9, -174.404, ruralModel},
+        {600000, true, 30.0e9, -177.925, ruralModel},
+        {600000, true, 2.0e9, -156.233, ruralModel},
+        {1200000, true, 20.0e9, -180.424, ruralModel},
+        {1200000, true, 30.0e9, -183.946, ruralModel},
+        {1200000, true, 2.0e9, -162.253, ruralModel}};
+
+    // Call TestChannelGain on each test point
+    for (auto& point : testPoints)
+    {
+        TestChannelGain(point);
+    }
+}
+
+void
+ThreeGppNTNPropagationLossModelTestCase::TestChannelGain(TestPoint testPoint)
+{
+    // Create the nodes for BS and UT
+    NodeContainer nodes;
+    nodes.Create(2);
+
+    // Create the mobility models
+    Ptr<MobilityModel> a = CreateObject<GeocentricConstantPositionMobilityModel>();
+    nodes.Get(0)->AggregateObject(a);
+    Ptr<MobilityModel> b = CreateObject<GeocentricConstantPositionMobilityModel>();
+    nodes.Get(1)->AggregateObject(b);
+
+    // Set fixed position of one of the nodes
+    Vector posA = Vector(0.0, 0.0, 0.0);
+    a->SetPosition(posA);
+    Vector posB = Vector(0.0, 0.0, testPoint.m_distance);
+    b->SetPosition(posB);
+
+    // Declare condition model
+    Ptr<ChannelConditionModel> conditionModel;
+
+    // Set the channel condition using a deterministic channel condition model
+    if (testPoint.m_isLos)
+    {
+        conditionModel = CreateObject<AlwaysLosChannelConditionModel>();
+    }
+    else
+    {
+        conditionModel = CreateObject<NeverLosChannelConditionModel>();
+    }
+
+    testPoint.m_propagationLossModel->SetChannelConditionModel(conditionModel);
+    testPoint.m_propagationLossModel->SetAttribute("Frequency", DoubleValue(testPoint.m_frequency));
+    NS_TEST_EXPECT_MSG_EQ_TOL(testPoint.m_propagationLossModel->CalcRxPower(0.0, a, b),
+                              testPoint.m_pwrRxDbm,
+                              5e-3,
+                              "Obtained unexpected received power");
+
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup propagation-tests
+ *
+ * \brief 3GPP NTN Propagation models TestSuite
+ *
+ * This TestSuite tests the following models:
+ *   - ThreeGppNTNDenseUrbanPropagationLossModel
+ *   - ThreeGppNTNUrbanPropagationLossModel
+ *   - ThreeGppNTNSuburbanPropagationLossModel
+ *   - ThreeGppNTNRuralPropagationLossModel
+ */
+class ThreeGppNTNPropagationLossModelsTestSuite : public TestSuite
+{
+  public:
+    ThreeGppNTNPropagationLossModelsTestSuite();
+};
+
+ThreeGppNTNPropagationLossModelsTestSuite::ThreeGppNTNPropagationLossModelsTestSuite()
+    : TestSuite("three-gpp-ntn-propagation-loss-model", Type::UNIT)
+{
+    AddTestCase(new ThreeGppNTNPropagationLossModelTestCase(), Duration::QUICK);
+}
+
+/// Static variable for test initialization
+static ThreeGppNTNPropagationLossModelsTestSuite g_propagationLossModelsTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc ns-3.42/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc
--- ns-3.41/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/propagation/test/three-gpp-propagation-loss-model-test-suite.cc	2024-05-29 15:29:47.160073800 -0700
@@ -167,10 +167,8 @@
         CreateObject<ThreeGppRmaPropagationLossModel>();
     lossModel->SetAttribute("ShadowingEnabled", BooleanValue(false)); // disable the shadow fading
 
-    for (std::size_t i = 0; i < m_testVectors.GetN(); i++)
+    for (const auto& testVector : m_testVectors)
     {
-        TestVector testVector = m_testVectors.Get(i);
-
         Vector posBs = Vector(0.0, 0.0, 35.0);
         Vector posUt = Vector(testVector.m_distance, 0.0, 1.5);
 
@@ -1325,15 +1323,15 @@
 };
 
 ThreeGppPropagationLossModelsTestSuite::ThreeGppPropagationLossModelsTestSuite()
-    : TestSuite("three-gpp-propagation-loss-model", UNIT)
+    : TestSuite("three-gpp-propagation-loss-model", Type::UNIT)
 {
-    AddTestCase(new ThreeGppRmaPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new ThreeGppUmaPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new ThreeGppUmiPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new ThreeGppIndoorOfficePropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new ThreeGppV2vUrbanPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new ThreeGppV2vHighwayPropagationLossModelTestCase, TestCase::QUICK);
-    AddTestCase(new ThreeGppShadowingTestCase, TestCase::QUICK);
+    AddTestCase(new ThreeGppRmaPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppUmaPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppUmiPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppIndoorOfficePropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppV2vUrbanPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppV2vHighwayPropagationLossModelTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppShadowingTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/doc/sixlowpan.rst ns-3.42/src/sixlowpan/doc/sixlowpan.rst
--- ns-3.41/src/sixlowpan/doc/sixlowpan.rst	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/sixlowpan/doc/sixlowpan.rst	2024-05-29 15:29:47.160073800 -0700
@@ -134,22 +134,19 @@
 ###############################################
 
 As the name implies, 6LoWPAN can handle only IPv6 packets. Any other protocol will be discarded.
-Moreover, 6LoWPAN assumes that the network is uniform, as is all the devices connected by the
-same same channel are using 6LoWPAN. Mixed environments are not supported by the standard.
-The reason is simple: 802.15.4 frame doesn't have a "protocol" field. As a consequence,
-there is no demultiplexing at MAC layer and the protocol carried by L2 frames must be known
-in advance.
 
-In the |ns3| implementation it is possible, but not advisable, to violate this requirement
-if the underlying NetDevice is capable of discriminating different protocols. As an example,
-CsmaNetDevice can carry IPv4 and 6LoWPAN at the same time. However, this configuration has
-not been tested.
+6LoWPAN can be used alongside other L3 protocols in networks supporting an EtherType (e.g.,
+Ethernet, WiFi, etc.). If the network does not have an EtherType in the frame header
+(like in the case of 802.15.4), then the network must be uniform, as is all the devices
+connected by the same same channel must use 6LoWPAN.
+
+The reason is simple: if the L2 frame doesn't have a "EtherType" field, then there is no
+demultiplexing at MAC layer and the protocol carried by L2 frames must be known
+in advance.
 
 References
 ==========
 
-.. [IANA802] IANA, assigned IEEE 802 numbers: http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xml
-.. [Ethertype] IEEE Ethertype numbers: http://standards.ieee.org/develop/regauth/ethertype/eth.txt
 .. [Shelby] Z. Shelby and C. Bormann, 6LoWPAN: The Wireless Embedded Internet. Wiley, 2011. [Online]. Available: https://books.google.it/books?id=3Nm7ZCxscMQC
 
 Usage
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc ns-3.42/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc
--- ns-3.41/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/sixlowpan/examples/example-ping-lr-wpan-beacon.cc	2024-05-29 15:29:47.160073800 -0700
@@ -29,13 +29,14 @@
 #include <fstream>
 
 using namespace ns3;
+using namespace ns3::lrwpan;
 
 static void
 DataSentMacConfirm(Ptr<LrWpanNetDevice> device, McpsDataConfirmParams params)
 {
     // In the case of transmissions with the Ack flag activated, the transaction is only
     // successful if the Ack was received.
-    if (params.m_status == LrWpanMacStatus::SUCCESS)
+    if (params.m_status == MacStatus::SUCCESS)
     {
         std::cout << Simulator::Now().As(Time::S) << " | Node " << device->GetNode()->GetId()
                   << " | Transmission successfully sent\n";
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/model/sixlowpan-header.cc ns-3.42/src/sixlowpan/model/sixlowpan-header.cc
--- ns-3.41/src/sixlowpan/model/sixlowpan-header.cc	2024-02-09 14:44:08.457794000 -0800
+++ ns-3.42/src/sixlowpan/model/sixlowpan-header.cc	2024-05-29 15:29:47.160073800 -0700
@@ -144,8 +144,6 @@
         serializedSize += 16;
         break;
     case HC1_PIIC:
-        serializedSize += 8;
-        break;
     case HC1_PCII:
         serializedSize += 8;
         break;
@@ -158,8 +156,6 @@
         serializedSize += 16;
         break;
     case HC1_PIIC:
-        serializedSize += 8;
-        break;
     case HC1_PCII:
         serializedSize += 8;
         break;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/model/sixlowpan-net-device.cc ns-3.42/src/sixlowpan/model/sixlowpan-net-device.cc
--- ns-3.41/src/sixlowpan/model/sixlowpan-net-device.cc	2024-02-09 14:44:08.461794100 -0800
+++ ns-3.42/src/sixlowpan/model/sixlowpan-net-device.cc	2024-05-29 15:29:47.160073800 -0700
@@ -180,7 +180,7 @@
     m_node = nullptr;
 
     m_timeoutEventList.clear();
-    if (m_timeoutEvent.IsRunning())
+    if (m_timeoutEvent.IsPending())
     {
         m_timeoutEvent.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/test/sixlowpan-fragmentation-test.cc ns-3.42/src/sixlowpan/test/sixlowpan-fragmentation-test.cc
--- ns-3.41/src/sixlowpan/test/sixlowpan-fragmentation-test.cc	2024-02-09 14:44:08.461794100 -0800
+++ ns-3.42/src/sixlowpan/test/sixlowpan-fragmentation-test.cc	2024-05-29 15:29:47.160073800 -0700
@@ -492,9 +492,9 @@
 };
 
 SixlowpanFragmentationTestSuite::SixlowpanFragmentationTestSuite()
-    : TestSuite("sixlowpan-fragmentation", UNIT)
+    : TestSuite("sixlowpan-fragmentation", Type::UNIT)
 {
-    AddTestCase(new SixlowpanFragmentationTest(), TestCase::QUICK);
+    AddTestCase(new SixlowpanFragmentationTest(), TestCase::Duration::QUICK);
 }
 
 static SixlowpanFragmentationTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/test/sixlowpan-hc1-test.cc ns-3.42/src/sixlowpan/test/sixlowpan-hc1-test.cc
--- ns-3.41/src/sixlowpan/test/sixlowpan-hc1-test.cc	2024-02-09 14:44:08.461794100 -0800
+++ ns-3.42/src/sixlowpan/test/sixlowpan-hc1-test.cc	2024-05-29 15:29:47.160073800 -0700
@@ -225,9 +225,9 @@
 };
 
 SixlowpanHc1TestSuite::SixlowpanHc1TestSuite()
-    : TestSuite("sixlowpan-hc1", UNIT)
+    : TestSuite("sixlowpan-hc1", Type::UNIT)
 {
-    AddTestCase(new SixlowpanHc1ImplTest(), TestCase::QUICK);
+    AddTestCase(new SixlowpanHc1ImplTest(), TestCase::Duration::QUICK);
 }
 
 static SixlowpanHc1TestSuite g_sixlowpanHc1TestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/test/sixlowpan-iphc-stateful-test.cc ns-3.42/src/sixlowpan/test/sixlowpan-iphc-stateful-test.cc
--- ns-3.41/src/sixlowpan/test/sixlowpan-iphc-stateful-test.cc	2024-02-09 14:44:08.461794100 -0800
+++ ns-3.42/src/sixlowpan/test/sixlowpan-iphc-stateful-test.cc	2024-05-29 15:29:47.160073800 -0700
@@ -390,9 +390,9 @@
 };
 
 SixlowpanIphcStatefulTestSuite::SixlowpanIphcStatefulTestSuite()
-    : TestSuite("sixlowpan-iphc-stateful", UNIT)
+    : TestSuite("sixlowpan-iphc-stateful", Type::UNIT)
 {
-    AddTestCase(new SixlowpanIphcStatefulImplTest(), TestCase::QUICK);
+    AddTestCase(new SixlowpanIphcStatefulImplTest(), TestCase::Duration::QUICK);
 }
 
 static SixlowpanIphcStatefulTestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/sixlowpan/test/sixlowpan-iphc-test.cc ns-3.42/src/sixlowpan/test/sixlowpan-iphc-test.cc
--- ns-3.41/src/sixlowpan/test/sixlowpan-iphc-test.cc	2024-02-09 14:44:08.461794100 -0800
+++ ns-3.42/src/sixlowpan/test/sixlowpan-iphc-test.cc	2024-05-29 15:29:47.160073800 -0700
@@ -223,9 +223,9 @@
 };
 
 SixlowpanIphcTestSuite::SixlowpanIphcTestSuite()
-    : TestSuite("sixlowpan-iphc", UNIT)
+    : TestSuite("sixlowpan-iphc", Type::UNIT)
 {
-    AddTestCase(new SixlowpanIphcImplTest(), TestCase::QUICK);
+    AddTestCase(new SixlowpanIphcImplTest(), TestCase::Duration::QUICK);
 }
 
 static SixlowpanIphcTestSuite g_sixlowpanIphcTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/CMakeLists.txt ns-3.42/src/spectrum/CMakeLists.txt
--- ns-3.41/src/spectrum/CMakeLists.txt	2024-02-09 14:44:08.461794100 -0800
+++ ns-3.42/src/spectrum/CMakeLists.txt	2024-05-29 15:29:47.164073700 -0700
@@ -36,7 +36,6 @@
     model/trace-fading-loss-model.cc
     model/tv-spectrum-transmitter.cc
     model/waveform-generator.cc
-    model/wifi-spectrum-value-helper.cc
 )
 
 set(header_files
@@ -77,7 +76,6 @@
     model/trace-fading-loss-model.h
     model/tv-spectrum-transmitter.h
     model/waveform-generator.h
-    model/wifi-spectrum-value-helper.h
     test/spectrum-test.h
 )
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/doc/spectrum.rst ns-3.42/src/spectrum/doc/spectrum.rst
--- ns-3.41/src/spectrum/doc/spectrum.rst	2024-02-09 14:44:08.465794000 -0800
+++ ns-3.42/src/spectrum/doc/spectrum.rst	2024-05-29 15:29:47.164073700 -0700
@@ -743,7 +743,7 @@
 receive antenna ports, the number transmit antenna ports, and
 the number of clusters. When multiple ports are being configured note that
 the sub-array partition model is adopted for TXRU virtualization, as described
-in Section 5.2.2 of 3GPP TR 36.897[TR36897]_, and so equal beam weights are used for all the ports.
+in Section 5.2.2 of 3GPP TR 36.897 [TR36897]_, and so equal beam weights are used for all the ports.
 Support of the full-connection model for TXRU virtualization would need extensions.
 To reduce the computational load, the long term
 components associated to the different channels are stored in the m_longTermMap
@@ -768,7 +768,7 @@
 (by default it is set to 0, so that the scattering effect is not considered).
 Function GenSpectrumChannelMatrix generates the received PSD for each pair of
 the transmit and receive antenna ports. It creates a frequency domain 3D spectrum
-channel matrix whose dimensions are the number of receive antena ports,
+channel matrix whose dimensions are the number of receive antenna ports,
 the number of transmit antenna ports, and the number of resource blocks.
 Finally, the frequency domain 3D spectrum channel matrix is used to obtain the
 received PSD. In case of multiple ports at the transmitter the PSD is calculated
@@ -813,8 +813,8 @@
 of a single cluster. This differs from a complete blockage, which
 would result in an LOS to NLOS transition. Therefore, when this
 feature is enabled, an additional attenuation is added to certain
-clusters, depending on their angle of arrival. There are two possi-
-ble methods for the computation of the additional attenuation, i.e.,
+clusters, depending on their angle of arrival. There are two possible
+methods for the computation of the additional attenuation, i.e.,
 stochastic (Model A) and geometric (Model B). In this work, we
 used the implementation provided by [Zhang]_, which
 uses the stochastic method. In particular, the model is implemented by the
@@ -1101,3 +1101,41 @@
    Mattias Frenne, Farshid Ghasemzadeh, Måns Hagström et al. Advanced Antenna Systems
    for 5G Network Deployments: Bridging the Gap Between Theory and Practice.
    Academic Press, 2020.
+
+
+3GPP TR 38.811 Non-Terrestrial Networks
+=======================================
+3GPP with [3GPPTR38811]_ has extended the channel model presented in [3GPPTR38901]_ to support the so called Non-Terrestrial Networks
+(NTN), i.e. communication scenarios where the propagation of the signal travels through the atmosphere.
+The channel spectrum estimation procedure is the same as the one described in [3GPPTR38901]_, with a new set of parameters.
+
+
+Use-cases
+#########
+The use-cases for this channel model include simulations in 3D/vertical environments with communicating nodes placed
+in different types of orbit, in the atmosphere and/or on the ground.
+
+Implementation
+##############
+The channel spectrum estimation procedure is already implemented (as described in [ns3Zugno]_ ) into the classes
+ThreeGppChannelModel and ThreeGppSpectrumPropagationLossModel, that have been extended to support NTN through the
+introduction of the appropriate parameters.
+3GPP considers two frequencies of interest: S-band (2GHz) and Ka-band (20/30GHz). Many channel parameters are dependent
+on the frequency band in use, but no specific range of frequencies of these bands has been given by 3GPP. Hence, this
+implementation considers S-band anything below 13GHz, and Ka-band anything above it.
+Four propagation scenarios are identified, in decreasing order of building height and density: Dense Urban, Urban,
+Suburban and Rural. Channel estimation parameters are scenario-dependent.
+**Note**: For satellite, the parameters that describe the departure angle spread are 0. Thus, in the logarithmic scale
+at which these parameters are represented is :math:`-\infty`.
+
+References
+##########
+
+.. [ns3Zugno] Zugno Tommaso, Michele Polese, Natale Patriciello, Biljana Bojović,
+   Sandra Lagen, Michele Zorzi. "Implementation of a spatial channel model for ns-3."
+   In Proceedings of the 2020 Workshop on ns-3, pp. 49-56. 2020.
+
+.. [3GPPTR38901] 3GPP. 2018. TR 38.901. Study on channel for frequencies from 0.5 to
+   100 GHz. V.15.0.0. (2018-06).
+
+.. [3GPPTR38811] 3GPP. 2018. TR 38.811, Study on New Radio (NR) to support non-terrestrial networks, V15.4.0. (2020-09).
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/examples/CMakeLists.txt ns-3.42/src/spectrum/examples/CMakeLists.txt
--- ns-3.41/src/spectrum/examples/CMakeLists.txt	2024-02-09 14:44:08.493794200 -0800
+++ ns-3.42/src/spectrum/examples/CMakeLists.txt	2024-05-29 15:29:47.168073700 -0700
@@ -65,3 +65,12 @@
     ${libmobility}
     ${libspectrum}
 )
+
+build_lib_example(
+  NAME three-gpp-ntn-channel-example
+  SOURCE_FILES three-gpp-ntn-channel-example.cc
+  LIBRARIES_TO_LINK
+    ${libcore}
+    ${libmobility}
+    ${libspectrum}
+)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/examples/three-gpp-ntn-channel-example.cc ns-3.42/src/spectrum/examples/three-gpp-ntn-channel-example.cc
--- ns-3.41/src/spectrum/examples/three-gpp-ntn-channel-example.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/spectrum/examples/three-gpp-ntn-channel-example.cc	2024-05-29 15:29:47.168073700 -0700
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2023 SIGNET Lab, Department of Information Engineering,
+ * University of Padova
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file
+ * This example is a modified version of "three-gpp-channel-example", to include
+ * the 3GPP NTN channel model.
+ * Specifically, most changes (which are also highlighted throughout the code)
+ * impact the main method, and comprise:
+ * - the configuration of ad-hoc propagation and channel condition models;
+ * - the use of GeocentricConstantPositionMobilityModel for the nodes mobility.
+ * The pre-configured parameters are the one provided by 3GPP in TR 38.821,
+ * more specifically scenario 10 in down-link mode.
+ * Two static nodes, one on the ground and one in orbit, communicate with each other.
+ * The carrier frequency is set at 20GHz with 400MHz bandwidth.
+ * The result is the SNR of the signal and the path loss, saved in the ntn-snr-trace.txt file.
+ */
+
+#include "ns3/channel-condition-model.h"
+#include "ns3/constant-position-mobility-model.h"
+#include "ns3/core-module.h"
+#include "ns3/geocentric-constant-position-mobility-model.h"
+#include "ns3/isotropic-antenna-model.h"
+#include "ns3/mobility-model.h"
+#include "ns3/net-device.h"
+#include "ns3/node-container.h"
+#include "ns3/node.h"
+#include "ns3/parabolic-antenna-model.h"
+#include "ns3/simple-net-device.h"
+#include "ns3/spectrum-signal-parameters.h"
+#include "ns3/three-gpp-channel-model.h"
+#include "ns3/three-gpp-propagation-loss-model.h"
+#include "ns3/three-gpp-spectrum-propagation-loss-model.h"
+#include "ns3/uniform-planar-array.h"
+#include <ns3/antenna-model.h>
+
+#include <fstream>
+
+NS_LOG_COMPONENT_DEFINE("NTNChannelExample");
+
+using namespace ns3;
+
+static Ptr<ThreeGppPropagationLossModel>
+    m_propagationLossModel; //!< the PropagationLossModel object
+static Ptr<ThreeGppSpectrumPropagationLossModel>
+    m_spectrumLossModel; //!< the SpectrumPropagationLossModel object
+
+/**
+ * @brief Create the PSD for the TX
+ *
+ * @param fcHz the carrier frequency in Hz
+ * @param pwrDbm the transmission power in dBm
+ * @param bwHz the bandwidth in Hz
+ * @param rbWidthHz the Resource Block (RB) width in Hz
+ *
+ * @return the pointer to the PSD
+ */
+Ptr<SpectrumValue>
+CreateTxPowerSpectralDensity(double fcHz, double pwrDbm, double bwHz, double rbWidthHz)
+{
+    unsigned int numRbs = std::floor(bwHz / rbWidthHz);
+    double f = fcHz - (numRbs * rbWidthHz / 2.0);
+    double powerTx = pwrDbm; // dBm power
+
+    Bands rbs; // A vector representing each resource block
+    for (uint32_t numrb = 0; numrb < numRbs; ++numrb)
+    {
+        BandInfo rb;
+        rb.fl = f;
+        f += rbWidthHz / 2;
+        rb.fc = f;
+        f += rbWidthHz / 2;
+        rb.fh = f;
+
+        rbs.push_back(rb);
+    }
+    Ptr<SpectrumModel> model = Create<SpectrumModel>(rbs);
+    Ptr<SpectrumValue> txPsd = Create<SpectrumValue>(model);
+
+    double powerTxW = std::pow(10., (powerTx - 30) / 10); // Get Tx power in Watts
+    double txPowerDensity = (powerTxW / bwHz);
+
+    for (auto psd = txPsd->ValuesBegin(); psd != txPsd->ValuesEnd(); ++psd)
+    {
+        *psd = txPowerDensity;
+    }
+
+    return txPsd; // [W/Hz]
+}
+
+/**
+ * @brief Create the noise PSD for the
+ *
+ * @param fcHz the carrier frequency in Hz
+ * @param noiseFigureDb the noise figure in dB
+ * @param bwHz the bandwidth in Hz
+ * @param rbWidthHz the Resource Block (RB) width in Hz
+ *
+ * @return the pointer to the noise PSD
+ */
+Ptr<SpectrumValue>
+CreateNoisePowerSpectralDensity(double fcHz, double noiseFigureDb, double bwHz, double rbWidthHz)
+{
+    unsigned int numRbs = std::floor(bwHz / rbWidthHz);
+    double f = fcHz - (numRbs * rbWidthHz / 2.0);
+
+    Bands rbs;              // A vector representing each resource block
+    std::vector<int> rbsId; // A vector representing the resource block IDs
+    for (uint32_t numrb = 0; numrb < numRbs; ++numrb)
+    {
+        BandInfo rb;
+        rb.fl = f;
+        f += rbWidthHz / 2;
+        rb.fc = f;
+        f += rbWidthHz / 2;
+        rb.fh = f;
+
+        rbs.push_back(rb);
+        rbsId.push_back(numrb);
+    }
+    Ptr<SpectrumModel> model = Create<SpectrumModel>(rbs);
+    Ptr<SpectrumValue> txPsd = Create<SpectrumValue>(model);
+
+    // see "LTE - From theory to practice"
+    // Section 22.4.4.2 Thermal Noise and Receiver Noise Figure
+    const double ktDbmHz = -174.0;                        // dBm/Hz
+    double ktWHz = std::pow(10.0, (ktDbmHz - 30) / 10.0); // W/Hz
+    double noiseFigureLinear = std::pow(10.0, noiseFigureDb / 10.0);
+
+    double noisePowerSpectralDensity = ktWHz * noiseFigureLinear;
+
+    for (auto rbId : rbsId)
+    {
+        (*txPsd)[rbId] = noisePowerSpectralDensity;
+    }
+
+    return txPsd; // W/Hz
+}
+
+/**
+ * \brief A structure that holds the parameters for the
+ * ComputeSnr function. In this way the problem with the limited
+ * number of parameters of method Schedule is avoided.
+ */
+struct ComputeSnrParams
+{
+    Ptr<MobilityModel> txMob;        //!< the tx mobility model
+    Ptr<MobilityModel> rxMob;        //!< the rx mobility model
+    double txPow;                    //!< the tx power in dBm
+    double noiseFigure;              //!< the noise figure in dB
+    Ptr<PhasedArrayModel> txAntenna; //!< the tx antenna array
+    Ptr<PhasedArrayModel> rxAntenna; //!< the rx antenna array
+    double frequency;                //!< the carrier frequency in Hz
+    double bandwidth;                //!< the total bandwidth in Hz
+    double resourceBlockBandwidth;   //!< the Resource Block bandwidth in Hz
+
+    /**
+     * \brief Constructor
+     * \param pTxMob the tx mobility model
+     * \param pRxMob the rx mobility model
+     * \param pTxPow the tx power in dBm
+     * \param pNoiseFigure the noise figure in dB
+     * \param pTxAntenna the tx antenna array
+     * \param pRxAntenna the rx antenna array
+     * \param pFrequency the carrier frequency in Hz
+     * \param pBandwidth the total bandwidth in Hz
+     * \param pResourceBlockBandwidth the Resource Block bandwidth in Hz
+     */
+    ComputeSnrParams(Ptr<MobilityModel> pTxMob,
+                     Ptr<MobilityModel> pRxMob,
+                     double pTxPow,
+                     double pNoiseFigure,
+                     Ptr<PhasedArrayModel> pTxAntenna,
+                     Ptr<PhasedArrayModel> pRxAntenna,
+                     double pFrequency,
+                     double pBandwidth,
+                     double pResourceBlockBandwidth)
+    {
+        txMob = pTxMob;
+        rxMob = pRxMob;
+        txPow = pTxPow;
+        noiseFigure = pNoiseFigure;
+        txAntenna = pTxAntenna;
+        rxAntenna = pRxAntenna;
+        frequency = pFrequency;
+        bandwidth = pBandwidth;
+        resourceBlockBandwidth = pResourceBlockBandwidth;
+    }
+};
+
+/**
+ * Perform the beamforming using the DFT beamforming method
+ * \param thisDevice the device performing the beamforming
+ * \param thisAntenna the antenna object associated to thisDevice
+ * \param otherDevice the device towards which point the beam
+ */
+static void
+DoBeamforming(Ptr<NetDevice> thisDevice,
+              Ptr<PhasedArrayModel> thisAntenna,
+              Ptr<NetDevice> otherDevice)
+{
+    // retrieve the position of the two devices
+    Vector aPos = thisDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
+    Vector bPos = otherDevice->GetNode()->GetObject<MobilityModel>()->GetPosition();
+
+    // compute the azimuth and the elevation angles
+    Angles completeAngle(bPos, aPos);
+    double hAngleRadian = completeAngle.GetAzimuth();
+    double vAngleRadian = completeAngle.GetInclination(); // the elevation angle
+
+    // retrieve the number of antenna elements and resize the vector
+    uint64_t totNoArrayElements = thisAntenna->GetNumElems();
+    PhasedArrayModel::ComplexVector antennaWeights(totNoArrayElements);
+
+    // the total power is divided equally among the antenna elements
+    double power = 1.0 / sqrt(totNoArrayElements);
+
+    // compute the antenna weights
+    const double sinVAngleRadian = sin(vAngleRadian);
+    const double cosVAngleRadian = cos(vAngleRadian);
+    const double sinHAngleRadian = sin(hAngleRadian);
+    const double cosHAngleRadian = cos(hAngleRadian);
+
+    for (uint64_t ind = 0; ind < totNoArrayElements; ind++)
+    {
+        Vector loc = thisAntenna->GetElementLocation(ind);
+        double phase = -2 * M_PI *
+                       (sinVAngleRadian * cosHAngleRadian * loc.x +
+                        sinVAngleRadian * sinHAngleRadian * loc.y + cosVAngleRadian * loc.z);
+        antennaWeights[ind] = exp(std::complex<double>(0, phase)) * power;
+    }
+
+    // store the antenna weights
+    thisAntenna->SetBeamformingVector(antennaWeights);
+}
+
+/**
+ * Compute the average SNR
+ * \param params A structure that holds the parameters that are needed to perform calculations in
+ * ComputeSnr
+ */
+static void
+ComputeSnr(ComputeSnrParams& params)
+{
+    Ptr<SpectrumValue> txPsd = CreateTxPowerSpectralDensity(params.frequency,
+                                                            params.txPow,
+                                                            params.bandwidth,
+                                                            params.resourceBlockBandwidth);
+    Ptr<SpectrumValue> rxPsd = txPsd->Copy();
+    NS_LOG_DEBUG("Average tx power " << 10 * log10(Sum(*txPsd) * params.resourceBlockBandwidth)
+                                     << " dB");
+
+    // create the noise PSD
+    Ptr<SpectrumValue> noisePsd = CreateNoisePowerSpectralDensity(params.frequency,
+                                                                  params.noiseFigure,
+                                                                  params.bandwidth,
+                                                                  params.resourceBlockBandwidth);
+    NS_LOG_DEBUG("Average noise power "
+                 << 10 * log10(Sum(*noisePsd) * params.resourceBlockBandwidth) << " dB");
+
+    // apply the pathloss
+    double propagationGainDb = m_propagationLossModel->CalcRxPower(0, params.txMob, params.rxMob);
+    NS_LOG_DEBUG("Pathloss " << -propagationGainDb << " dB");
+    double propagationGainLinear = std::pow(10.0, (propagationGainDb) / 10.0);
+    *(rxPsd) *= propagationGainLinear;
+
+    NS_ASSERT_MSG(params.txAntenna, "params.txAntenna is nullptr!");
+    NS_ASSERT_MSG(params.rxAntenna, "params.rxAntenna is nullptr!");
+
+    Ptr<SpectrumSignalParameters> rxSsp = Create<SpectrumSignalParameters>();
+    rxSsp->psd = rxPsd;
+    rxSsp->txAntenna =
+        ConstCast<AntennaModel, const AntennaModel>(params.txAntenna->GetAntennaElement());
+
+    // apply the fast fading and the beamforming gain
+    rxSsp = m_spectrumLossModel->CalcRxPowerSpectralDensity(rxSsp,
+                                                            params.txMob,
+                                                            params.rxMob,
+                                                            params.txAntenna,
+                                                            params.rxAntenna);
+    NS_LOG_DEBUG("Average rx power " << 10 * log10(Sum(*rxSsp->psd) * params.bandwidth) << " dB");
+
+    // compute the SNR
+    NS_LOG_DEBUG("Average SNR " << 10 * log10(Sum(*rxSsp->psd) / Sum(*noisePsd)) << " dB");
+
+    // print the SNR and pathloss values in the ntn-snr-trace.txt file
+    std::ofstream f;
+    f.open("ntn-snr-trace.txt", std::ios::out | std::ios::app);
+    f << Simulator::Now().GetSeconds() << " " << 10 * log10(Sum(*rxSsp->psd) / Sum(*noisePsd))
+      << " " << propagationGainDb << std::endl;
+    f.close();
+}
+
+int
+main(int argc, char* argv[])
+{
+    uint32_t simTimeMs = 1000; // simulation time in milliseconds
+    uint32_t timeResMs = 10;   // time resolution in milliseconds
+
+    // Start changes with respect to three-gpp-channel-example
+    // SCENARIO 10 DL of TR 38.321
+    // This parameters can be set accordingly to 3GPP TR 38.821 or arbitrarily modified
+    std::string scenario = "NTN-Suburban"; // 3GPP propagation scenario
+    // All available NTN scenarios: DenseUrban, Urban, Suburban, Rural.
+
+    double frequencyHz = 20e9;    // operating frequency in Hz
+    double bandwidthHz = 400e6;   // Hz
+    double RbBandwidthHz = 120e3; // Hz
+
+    // Satellite parameters
+    double satEIRPDensity = 40;     // dBW/MHz
+    double satAntennaGainDb = 58.5; // dB
+
+    // UE Parameters
+    double vsatAntennaGainDb = 39.7;       // dB
+    double vsatAntennaNoiseFigureDb = 1.2; // dB
+    // End changes with respect to three-gpp-channel-example
+
+    /* Command line argument parser setup. */
+    CommandLine cmd(__FILE__);
+    cmd.AddValue("scenario",
+                 "The 3GPP NTN scenario to use. Valid options are: "
+                 "NTN-DenseUrban, NTN-Urban, NTN-Suburban, and NTN-Rural",
+                 scenario);
+    cmd.AddValue("frequencyHz", "The carrier frequency in Hz", frequencyHz);
+    cmd.AddValue("bandwidthHz", "The bandwidth in Hz", bandwidthHz);
+    cmd.AddValue("satEIRPDensity", "The satellite EIRP density in dBW/MHz", satEIRPDensity);
+    cmd.AddValue("satAntennaGainDb", "The satellite antenna gain in dB", satAntennaGainDb);
+    cmd.AddValue("vsatAntennaGainDb", "The UE VSAT antenna gain in dB", vsatAntennaGainDb);
+    cmd.AddValue("vsatAntennaNoiseFigureDb",
+                 "The UE VSAT antenna noise figure in dB",
+                 vsatAntennaNoiseFigureDb);
+    cmd.Parse(argc, argv);
+
+    // Calculate transmission power in dBm using EIRPDensity + 10*log10(Bandwidth) - AntennaGain +
+    // 30
+    double txPowDbm = (satEIRPDensity + 10 * log10(bandwidthHz / 1e6) - satAntennaGainDb) + 30;
+
+    NS_LOG_DEBUG("Transmitting power: " << txPowDbm << "dBm, (" << pow(10., (txPowDbm - 30) / 10)
+                                        << "W)");
+
+    Config::SetDefault("ns3::ThreeGppChannelModel::UpdatePeriod",
+                       TimeValue(MilliSeconds(10))); // update the channel at every 10 ms
+    Config::SetDefault("ns3::ThreeGppChannelConditionModel::UpdatePeriod",
+                       TimeValue(MilliSeconds(0.0))); // do not update the channel condition
+
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(1);
+
+    // create and configure the factories for the channel condition and propagation loss models
+    ObjectFactory propagationLossModelFactory;
+    ObjectFactory channelConditionModelFactory;
+
+    // Start changes with respect to three-gpp-channel-example
+    if (scenario == "NTN-DenseUrban")
+    {
+        propagationLossModelFactory.SetTypeId(
+            ThreeGppNTNDenseUrbanPropagationLossModel::GetTypeId());
+        channelConditionModelFactory.SetTypeId(
+            ThreeGppNTNDenseUrbanChannelConditionModel::GetTypeId());
+    }
+    else if (scenario == "NTN-Urban")
+    {
+        propagationLossModelFactory.SetTypeId(ThreeGppNTNUrbanPropagationLossModel::GetTypeId());
+        channelConditionModelFactory.SetTypeId(ThreeGppNTNUrbanChannelConditionModel::GetTypeId());
+    }
+    else if (scenario == "NTN-Suburban")
+    {
+        propagationLossModelFactory.SetTypeId(ThreeGppNTNSuburbanPropagationLossModel::GetTypeId());
+        channelConditionModelFactory.SetTypeId(
+            ThreeGppNTNSuburbanChannelConditionModel::GetTypeId());
+    }
+    else if (scenario == "NTN-Rural")
+    {
+        propagationLossModelFactory.SetTypeId(ThreeGppNTNRuralPropagationLossModel::GetTypeId());
+        channelConditionModelFactory.SetTypeId(ThreeGppNTNRuralChannelConditionModel::GetTypeId());
+    }
+    else
+    {
+        NS_FATAL_ERROR("Unknown NTN scenario");
+    }
+    // End changes with respect to three-gpp-channel-example
+
+    // create the propagation loss model
+    m_propagationLossModel = propagationLossModelFactory.Create<ThreeGppPropagationLossModel>();
+    m_propagationLossModel->SetAttribute("Frequency", DoubleValue(frequencyHz));
+    m_propagationLossModel->SetAttribute("ShadowingEnabled", BooleanValue(true));
+
+    // create the spectrum propagation loss model
+    m_spectrumLossModel = CreateObject<ThreeGppSpectrumPropagationLossModel>();
+    m_spectrumLossModel->SetChannelModelAttribute("Frequency", DoubleValue(frequencyHz));
+    m_spectrumLossModel->SetChannelModelAttribute("Scenario", StringValue(scenario));
+
+    // create the channel condition model and associate it with the spectrum and
+    // propagation loss model
+    Ptr<ChannelConditionModel> condModel =
+        channelConditionModelFactory.Create<ThreeGppChannelConditionModel>();
+    m_spectrumLossModel->SetChannelModelAttribute("ChannelConditionModel", PointerValue(condModel));
+    m_propagationLossModel->SetChannelConditionModel(condModel);
+
+    // create the tx and rx nodes
+    NodeContainer nodes;
+    nodes.Create(2);
+
+    // create the tx and rx devices
+    Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
+    Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
+
+    // associate the nodes and the devices
+    nodes.Get(0)->AddDevice(txDev);
+    txDev->SetNode(nodes.Get(0));
+    nodes.Get(1)->AddDevice(rxDev);
+    rxDev->SetNode(nodes.Get(1));
+
+    // Start changes with respect to three-gpp-channel-example, here a mobility model
+    // tailored to NTN scenarios is used (GeocentricConstantPositionMobilityModel)
+    // create the tx and rx mobility models, set the positions
+    Ptr<GeocentricConstantPositionMobilityModel> txMob =
+        CreateObject<GeocentricConstantPositionMobilityModel>();
+    Ptr<GeocentricConstantPositionMobilityModel> rxMob =
+        CreateObject<GeocentricConstantPositionMobilityModel>();
+
+    txMob->SetGeographicPosition(Vector(45.40869, 11.89448, 35786000)); // GEO over Padova
+    rxMob->SetGeographicPosition(Vector(45.40869, 11.89448, 14.0));     // Padova Coordinates
+
+    // This is not strictly necessary, but is useful to have "sensible" values when using
+    // GetPosition()
+    txMob->SetCoordinateTranslationReferencePoint(
+        Vector(45.40869, 11.89448, 0.0)); // Padova Coordinates without altitude
+    rxMob->SetCoordinateTranslationReferencePoint(
+        Vector(45.40869, 11.89448, 0.0)); // Padova Coordinates without altitude
+    // End changes with respect to three-gpp-channel-example,
+
+    NS_LOG_DEBUG("TX Position: " << txMob->GetPosition());
+    NS_LOG_DEBUG("RX Position: " << rxMob->GetPosition());
+
+    // assign the mobility models to the nodes
+    nodes.Get(0)->AggregateObject(txMob);
+    nodes.Get(1)->AggregateObject(rxMob);
+
+    // Start changes with respect to three-gpp-channel-example,
+    // Here antenna models mimic the gain achieved by the CircularApertureAntennaModel,
+    // which is not used to avoid inheriting the latter's dependence on either libstdc++
+    // or Boost.
+    Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
+        "NumColumns",
+        UintegerValue(1),
+        "NumRows",
+        UintegerValue(1),
+        "AntennaElement",
+        PointerValue(
+            CreateObjectWithAttributes<IsotropicAntennaModel>("Gain",
+                                                              DoubleValue(satAntennaGainDb))));
+
+    Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
+        "NumColumns",
+        UintegerValue(1),
+        "NumRows",
+        UintegerValue(1),
+        "AntennaElement",
+        PointerValue(
+            CreateObjectWithAttributes<IsotropicAntennaModel>("Gain",
+                                                              DoubleValue(vsatAntennaGainDb))));
+    // End changes with respect to three-gpp-channel-example
+
+    // set the beamforming vectors
+    DoBeamforming(rxDev, rxAntenna, txDev);
+    DoBeamforming(txDev, txAntenna, rxDev);
+
+    for (int i = 0; i < floor(simTimeMs / timeResMs); i++)
+    {
+        Simulator::Schedule(MilliSeconds(timeResMs * i),
+                            &ComputeSnr,
+                            ComputeSnrParams(txMob,
+                                             rxMob,
+                                             txPowDbm,
+                                             vsatAntennaNoiseFigureDb,
+                                             txAntenna,
+                                             rxAntenna,
+                                             frequencyHz,
+                                             bandwidthHz,
+                                             RbBandwidthHz));
+    }
+
+    Simulator::Run();
+    Simulator::Destroy();
+    return 0;
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/aloha-noack-net-device.cc ns-3.42/src/spectrum/model/aloha-noack-net-device.cc
--- ns-3.41/src/spectrum/model/aloha-noack-net-device.cc	2024-02-09 14:44:08.493794200 -0800
+++ ns-3.42/src/spectrum/model/aloha-noack-net-device.cc	2024-05-29 15:29:47.168073700 -0700
@@ -206,7 +206,7 @@
 AlohaNoackNetDevice::GetBroadcast() const
 {
     NS_LOG_FUNCTION(this);
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/half-duplex-ideal-phy.cc ns-3.42/src/spectrum/model/half-duplex-ideal-phy.cc
--- ns-3.41/src/spectrum/model/half-duplex-ideal-phy.cc	2024-02-09 14:44:08.493794200 -0800
+++ ns-3.42/src/spectrum/model/half-duplex-ideal-phy.cc	2024-05-29 15:29:47.168073700 -0700
@@ -348,7 +348,6 @@
         {
         case TX:
             // the PHY will not notice this incoming signal
-            break;
 
         case RX:
             // we should check if we should re-sync on a new incoming signal and discard the old one
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/matrix-based-channel-model.h ns-3.42/src/spectrum/model/matrix-based-channel-model.h
--- ns-3.41/src/spectrum/model/matrix-based-channel-model.h	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/matrix-based-channel-model.h	2024-05-29 15:29:47.168073700 -0700
@@ -93,11 +93,6 @@
         std::pair<uint32_t, uint32_t> m_nodeIds;
 
         /**
-         * Destructor for ChannelMatrix
-         */
-        virtual ~ChannelMatrix() = default;
-
-        /**
          * Returns true if the ChannelMatrix object was generated
          * considering node b as transmitter and node a as receiver.
          * \param aAntennaId the ID of the antenna array of the a node
@@ -139,6 +134,12 @@
         Double2DVector m_angle;
 
         /**
+         * Sin/cos of cluster angle angle[direction][n], where direction = 0(AOA), 1(ZOA), 2(AOD),
+         * 3(ZOD) in degree.
+         */
+        std::vector<std::vector<std::pair<double, double>>> m_cachedAngleSincos;
+
+        /**
          * Alpha term per cluster as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
          * for calculating doppler.
          */
@@ -158,6 +159,19 @@
         std::pair<uint32_t, uint32_t> m_nodeIds;
 
         /**
+         * Auxiliary variable to m_cachedDelaySincos
+         *
+         * It is used to determine RB width (12*SCS) changes due to numerology,
+         * in case the number of the RBs in the channel remains constant.
+         */
+        mutable double m_cachedRbWidth = 0.0;
+
+        /**
+         * Matrix array that holds the precomputed delay sincos
+         */
+        mutable ComplexMatrixArray m_cachedDelaySincos;
+
+        /**
          * Destructor for ChannelParams
          */
         virtual ~ChannelParams() = default;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/multi-model-spectrum-channel.cc ns-3.42/src/spectrum/model/multi-model-spectrum-channel.cc
--- ns-3.41/src/spectrum/model/multi-model-spectrum-channel.cc	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/multi-model-spectrum-channel.cc	2024-05-29 15:29:47.168073700 -0700
@@ -210,7 +210,6 @@
             {
                 NS_LOG_LOGIC("Creating converter between SpectrumModelUid "
                              << txSpectrumModelUid << " and " << rxSpectrumModelUid);
-
                 SpectrumConverter converter(txSpectrumModel, rxSpectrumModel);
                 auto ret2 = txInfoIterator->second.m_spectrumConverterMap.insert(
                     std::make_pair(rxSpectrumModelUid, converter));
@@ -237,21 +236,10 @@
                           // underlying DynamicCasts)
     m_txSigParamsTrace(txParamsTrace);
 
-    Ptr<MobilityModel> txMobility = txParams->txPhy->GetMobility();
-    SpectrumModelUid_t txSpectrumModelUid = txParams->psd->GetSpectrumModelUid();
+    auto txMobility = txParams->txPhy->GetMobility();
+    auto txSpectrumModelUid = txParams->psd->GetSpectrumModelUid();
     NS_LOG_LOGIC("txSpectrumModelUid " << txSpectrumModelUid);
 
-    //
-    auto txInfoIteratorerator =
-        FindAndEventuallyAddTxSpectrumModel(txParams->psd->GetSpectrumModel());
-    NS_ASSERT(txInfoIteratorerator != m_txSpectrumModelInfoMap.end());
-
-    NS_LOG_LOGIC("converter map for TX SpectrumModel with Uid " << txInfoIteratorerator->first);
-    NS_LOG_LOGIC(
-        "converter map size: " << txInfoIteratorerator->second.m_spectrumConverterMap.size());
-    NS_LOG_LOGIC("converter map first element: "
-                 << txInfoIteratorerator->second.m_spectrumConverterMap.begin()->first);
-
     for (auto rxInfoIterator = m_rxSpectrumModelInfoMap.begin();
          rxInfoIterator != m_rxSpectrumModelInfoMap.end();
          ++rxInfoIterator)
@@ -259,26 +247,6 @@
         SpectrumModelUid_t rxSpectrumModelUid = rxInfoIterator->second.m_rxSpectrumModel->GetUid();
         NS_LOG_LOGIC("rxSpectrumModelUids " << rxSpectrumModelUid);
 
-        Ptr<SpectrumValue> convertedTxPowerSpectrum;
-        if (txSpectrumModelUid == rxSpectrumModelUid)
-        {
-            NS_LOG_LOGIC("no spectrum conversion needed");
-            convertedTxPowerSpectrum = txParams->psd;
-        }
-        else
-        {
-            NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
-                         << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
-            auto rxConverterIterator =
-                txInfoIteratorerator->second.m_spectrumConverterMap.find(rxSpectrumModelUid);
-            if (rxConverterIterator == txInfoIteratorerator->second.m_spectrumConverterMap.end())
-            {
-                // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
-                continue;
-            }
-            convertedTxPowerSpectrum = rxConverterIterator->second.Convert(txParams->psd);
-        }
-
         for (auto rxPhyIterator = rxInfoIterator->second.m_rxPhys.begin();
              rxPhyIterator != rxInfoIterator->second.m_rxPhys.end();
              ++rxPhyIterator)
@@ -289,8 +257,8 @@
 
             if ((*rxPhyIterator) != txParams->txPhy)
             {
-                Ptr<NetDevice> rxNetDevice = (*rxPhyIterator)->GetDevice();
-                Ptr<NetDevice> txNetDevice = txParams->txPhy->GetDevice();
+                auto rxNetDevice = (*rxPhyIterator)->GetDevice();
+                auto txNetDevice = txParams->txPhy->GetDevice();
 
                 if (rxNetDevice && txNetDevice)
                 {
@@ -310,18 +278,18 @@
                 }
 
                 NS_LOG_LOGIC("copying signal parameters " << txParams);
-                Ptr<SpectrumSignalParameters> rxParams = txParams->Copy();
-                rxParams->psd = Copy<SpectrumValue>(convertedTxPowerSpectrum);
-                Time delay = MicroSeconds(0);
+                auto rxParams = txParams->Copy();
+                rxParams->psd = Copy<SpectrumValue>(txParams->psd);
+                Time delay{0};
 
-                Ptr<MobilityModel> receiverMobility = (*rxPhyIterator)->GetMobility();
+                auto receiverMobility = (*rxPhyIterator)->GetMobility();
 
                 if (txMobility && receiverMobility)
                 {
-                    double txAntennaGain = 0;
-                    double rxAntennaGain = 0;
-                    double propagationGainDb = 0;
-                    double pathLossDb = 0;
+                    auto txAntennaGain{0.0};
+                    auto rxAntennaGain{0.0};
+                    auto propagationGainDb{0.0};
+                    auto pathLossDb{0.0};
                     if (rxParams->txAntenna)
                     {
                         Angles txAngles(receiverMobility->GetPosition(), txMobility->GetPosition());
@@ -329,8 +297,7 @@
                         NS_LOG_LOGIC("txAntennaGain = " << txAntennaGain << " dB");
                         pathLossDb -= txAntennaGain;
                     }
-                    Ptr<AntennaModel> rxAntenna =
-                        DynamicCast<AntennaModel>((*rxPhyIterator)->GetAntenna());
+                    auto rxAntenna = DynamicCast<AntennaModel>((*rxPhyIterator)->GetAntenna());
                     if (rxAntenna)
                     {
                         Angles rxAngles(txMobility->GetPosition(), receiverMobility->GetPosition());
@@ -360,7 +327,7 @@
                         // beyond range
                         continue;
                     }
-                    double pathGainLinear = std::pow(10.0, (-pathLossDb) / 10.0);
+                    auto pathGainLinear = std::pow(10.0, (-pathLossDb) / 10.0);
                     *(rxParams->psd) *= pathGainLinear;
 
                     if (m_propagationDelay)
@@ -372,7 +339,7 @@
                 if (rxNetDevice)
                 {
                     // the receiver has a NetDevice, so we expect that it is attached to a Node
-                    uint32_t dstNode = rxNetDevice->GetNode()->GetId();
+                    auto dstNode = rxNetDevice->GetNode()->GetId();
                     Simulator::ScheduleWithContext(dstNode,
                                                    delay,
                                                    &MultiModelSpectrumChannel::StartRx,
@@ -399,6 +366,40 @@
 MultiModelSpectrumChannel::StartRx(Ptr<SpectrumSignalParameters> params, Ptr<SpectrumPhy> receiver)
 {
     NS_LOG_FUNCTION(this);
+    const auto txSpectrumModelUid = params->psd->GetSpectrumModelUid();
+    const auto rxSpectrumModelUid = receiver->GetRxSpectrumModel()->GetUid();
+
+    auto txInfoIteratorerator =
+        FindAndEventuallyAddTxSpectrumModel(params->psd->GetSpectrumModel());
+    NS_ASSERT(txInfoIteratorerator != m_txSpectrumModelInfoMap.end());
+
+    NS_LOG_LOGIC("converter map for TX SpectrumModel with Uid " << txInfoIteratorerator->first);
+    NS_LOG_LOGIC(
+        "converter map size: " << txInfoIteratorerator->second.m_spectrumConverterMap.size());
+    NS_LOG_LOGIC("converter map first element: "
+                 << txInfoIteratorerator->second.m_spectrumConverterMap.begin()->first);
+
+    Ptr<SpectrumValue> convertedPsd;
+    if (txSpectrumModelUid == rxSpectrumModelUid)
+    {
+        NS_LOG_LOGIC("no spectrum conversion needed");
+        convertedPsd = params->psd;
+    }
+    else
+    {
+        NS_LOG_LOGIC("converting txPowerSpectrum SpectrumModelUids "
+                     << txSpectrumModelUid << " --> " << rxSpectrumModelUid);
+        auto rxConverterIterator =
+            txInfoIteratorerator->second.m_spectrumConverterMap.find(rxSpectrumModelUid);
+        if (rxConverterIterator == txInfoIteratorerator->second.m_spectrumConverterMap.end())
+        {
+            // No converter means TX SpectrumModel is orthogonal to RX SpectrumModel
+            return;
+        }
+        convertedPsd = rxConverterIterator->second.Convert(params->psd);
+        NS_LOG_LOGIC("convertedPsd " << convertedPsd->GetValuesN());
+    }
+    params->psd = convertedPsd;
     if (m_spectrumPropagationLoss)
     {
         params->psd =
@@ -408,10 +409,8 @@
     }
     else if (m_phasedArraySpectrumPropagationLoss)
     {
-        Ptr<const PhasedArrayModel> txPhasedArrayModel =
-            DynamicCast<PhasedArrayModel>(params->txPhy->GetAntenna());
-        Ptr<const PhasedArrayModel> rxPhasedArrayModel =
-            DynamicCast<PhasedArrayModel>(receiver->GetAntenna());
+        auto txPhasedArrayModel = DynamicCast<PhasedArrayModel>(params->txPhy->GetAntenna());
+        auto rxPhasedArrayModel = DynamicCast<PhasedArrayModel>(receiver->GetAntenna());
 
         NS_ASSERT_MSG(txPhasedArrayModel && rxPhasedArrayModel,
                       "PhasedArrayModel instances should be installed at both TX and RX "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/single-model-spectrum-channel.cc ns-3.42/src/spectrum/model/single-model-spectrum-channel.cc
--- ns-3.41/src/spectrum/model/single-model-spectrum-channel.cc	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/single-model-spectrum-channel.cc	2024-05-29 15:29:47.168073700 -0700
@@ -90,6 +90,11 @@
     {
         m_phyList.push_back(phy);
     }
+    else
+    {
+        // PHY has switched its channel, reset m_spectrumModel
+        m_spectrumModel = nullptr;
+    }
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/spectrum-value.cc ns-3.42/src/spectrum/model/spectrum-value.cc
--- ns-3.41/src/spectrum/model/spectrum-value.cc	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/spectrum-value.cc	2024-05-29 15:29:47.168073700 -0700
@@ -394,12 +394,20 @@
 operator<<(std::ostream& os, const SpectrumValue& pvf)
 {
     auto it1 = pvf.ConstValuesBegin();
+    bool first = true;
     while (it1 != pvf.ConstValuesEnd())
     {
-        os << *it1 << " ";
+        if (!first)
+        {
+            os << " ";
+        }
+        else
+        {
+            first = false;
+        }
+        os << *it1;
         ++it1;
     }
-    os << std::endl;
     return os;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/three-gpp-channel-model.cc ns-3.42/src/spectrum/model/three-gpp-channel-model.cc
--- ns-3.41/src/spectrum/model/three-gpp-channel-model.cc	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/three-gpp-channel-model.cc	2024-05-29 15:29:47.172073600 -0700
@@ -22,6 +22,7 @@
 #include "three-gpp-channel-model.h"
 
 #include "ns3/double.h"
+#include "ns3/geocentric-constant-position-mobility-model.h"
 #include "ns3/integer.h"
 #include "ns3/log.h"
 #include "ns3/mobility-model.h"
@@ -42,6 +43,9 @@
 
 NS_OBJECT_ENSURE_REGISTERED(ThreeGppChannelModel);
 
+/// Conversion factor: degrees to radians
+static constexpr double DEG2RAD = M_PI / 180.0;
+
 /// The ray offset angles within a cluster, given for rms angle spread normalized to 1.
 /// (Table 7.5-3)
 static const double offSetAlpha[20] = {
@@ -245,6 +249,832 @@
     {0, -0.069282, 0.295397, 0.430696, 0.468462, 0.709214},
 };
 
+/**
+ * The square root matrix for <em>NTN Dense Urban LOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-1 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const double sqrtC_NTN_DenseUrban_LOS[7][7] = {
+    {1, 0, 0, 0, 0, 0, 0},
+    {0, 1, 0, 0, 0, 0, 0},
+    {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
+    {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
+    {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
+    {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
+    {-0.8, 0, -0.388057, -0.367926, 0.238537, -4.09997e-15, 0.130931},
+};
+
+/**
+ * The square root matrix for <em>NTN Dense Urban NLOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-2 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const double sqrtC_NTN_DenseUrban_NLOS[6][6] = {
+    {1, 0, 0, 0, 0, 0},
+    {-0.4, 0.916515, 0, 0, 0, 0},
+    {-0.6, 0.174574, 0.78072, 0, 0, 0},
+    {0, 0.654654, 0.365963, 0.661438, 0, 0},
+    {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
+    {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
+};
+
+/**
+ * The square root matrix for <em>NTN Urban LOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-3 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const double sqrtC_NTN_Urban_LOS[7][7] = {
+    {1, 0, 0, 0, 0, 0, 0},
+    {0, 1, 0, 0, 0, 0, 0},
+    {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
+    {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
+    {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
+    {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
+    {-0.8, 0, -0.388057, -0.367926, 0.238537, -4.09997e-15, 0.130931},
+};
+
+/**
+ * The square root matrix for <em>NTN Urban NLOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-4 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The square root matrix is dependent on the elevation angle, thus requiring a map.
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const std::map<int, std::vector<std::vector<double>>> sqrtC_NTN_Urban_NLOS{
+    {10,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.21, 0.977701, 0, 0, 0, 0},
+         {-0.48, 0.459445, 0.747335, 0, 0, 0},
+         {-0.05, 0.377927, 0.28416, 0.879729, 0, 0},
+         {-0.02, 0.691213, 0.258017, 0.073265, 0.670734, 0},
+         {-0.31, -0.00521632, -0.115615, 0.0788023, 0.00218104, 0.940368},
+     }},
+    {20,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.25, 0.968246, 0, 0, 0, 0},
+         {-0.52, 0.35115, 0.778648, 0, 0, 0},
+         {-0.04, 0.371806, 0.345008, 0.860889, 0, 0},
+         {0, 0.743613, 0.281102, 0.0424415, 0.605161, 0},
+         {-0.32, 0.0206559, -0.0689057, 0.154832, 0.061865, 0.929852},
+     }},
+    {30,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.21, 0.977701, 0, 0, 0, 0},
+         {-0.52, 0.450853, 0.725487, 0, 0, 0},
+         {-0.04, 0.288023, 0.260989, 0.920504, 0, 0},
+         {0.01, 0.697657, 0.386856, 0.0418183, 0.601472, 0},
+         {-0.33, 0.0416283, -0.0694268, 0.166137, 0.139937, 0.915075},
+     }},
+    {40,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.26, 0.965609, 0, 0, 0, 0},
+         {-0.53, 0.395813, 0.749955, 0, 0, 0},
+         {-0.04, 0.299914, 0.320139, 0.897754, 0, 0},
+         {0.01, 0.696556, 0.372815, 0.0580784, 0.610202, 0},
+         {-0.33, 0.0457742, -0.0173584, 0.154417, 0.129332, 0.920941},
+     }},
+    {50,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.25, 0.968246, 0, 0, 0, 0},
+         {-0.57, 0.420864, 0.705672, 0, 0, 0},
+         {-0.03, 0.229797, 0.235501, 0.943839, 0, 0},
+         {0.03, 0.679063, 0.384466, 0.0681379, 0.6209, 0},
+         {-0.41, -0.147173, -0.229228, 0.270707, 0.293002, 0.773668},
+     }},
+    {60,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.2, 0.979796, 0, 0, 0, 0},
+         {-0.53, 0.473568, 0.703444, 0, 0, 0},
+         {-0.05, 0.204124, 0.109225, 0.971547, 0, 0},
+         {0.03, 0.68994, 0.411073, 0.0676935, 0.591202, 0},
+         {-0.4, -0.224537, -0.292371, 0.275609, 0.301835, 0.732828},
+     }},
+    {70,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.19, 0.981784, 0, 0, 0, 0},
+         {-0.5, 0.524555, 0.689088, 0, 0, 0},
+         {-0.03, 0.228462, 0.18163, 0.955989, 0, 0},
+         {-0.02, 0.637818, 0.428725, 0.00608114, 0.639489, 0},
+         {-0.36, -0.18171, -0.282523, 0.106726, 0.123808, 0.854894},
+     }},
+    {80,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.2, 0.979796, 0, 0, 0, 0},
+         {-0.49, 0.502145, 0.712566, 0, 0, 0},
+         {-0.01, 0.232702, 0.151916, 0.960558, 0, 0},
+         {-0.05, 0.612372, 0.376106, 0.0206792, 0.693265, 0},
+         {-0.37, -0.320475, -0.365405, -0.00376264, 0.0364343, 0.790907},
+     }},
+    {90,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.19, 0.981784, 0, 0, 0, 0},
+         {-0.38, 0.58852, 0.713613, 0, 0, 0},
+         {-0.03, 0.360874, 0.12082, 0.924269, 0, 0},
+         {-0.12, 0.526796, 0.34244, 0.0594196, 0.766348, 0},
+         {-0.33, -0.257389, -0.24372, -0.257035, -0.176521, 0.817451},
+     }},
+};
+
+/**
+ * The square root matrix for <em>NTN Suburban LOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-5 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const double sqrtC_NTN_Suburban_LOS[7][7] = {
+    {1, 0, 0, 0, 0, 0, 0},
+    {0, 1, 0, 0, 0, 0, 0},
+    {-0.4, -0.4, 0.824621, 0, 0, 0, 0},
+    {-0.5, 0, 0.242536, 0.83137, 0, 0, 0},
+    {-0.5, -0.2, 0.630593, -0.484671, 0.278293, 0, 0},
+    {0, 0, -0.242536, 0.672172, 0.642214, 0.27735, 0},
+    {-0.8, 0, -0.388057, -0.367926, 0.238537, -4.09997e-15, 0.130931},
+};
+
+/**
+ * The square root matrix for <em>NTN Suburban NLOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-6 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const double sqrtC_NTN_Suburban_NLOS[6][6] = {
+    {1, 0, 0, 0, 0, 0},
+    {-0.4, 0.916515, 0, 0, 0, 0},
+    {-0.6, 0.174574, 0.78072, 0, 0, 0},
+    {0, 0.654654, 0.365963, 0.661438, 0, 0},
+    {0, -0.545545, 0.762422, 0.118114, 0.327327, 0},
+    {-0.4, -0.174574, -0.396459, 0.392138, 0.49099, 0.507445},
+};
+
+/**
+ * The square root matrix for <em>NTN Rural LOS</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-7 and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const double sqrtC_NTN_Rural_LOS[7][7] = {
+    {1, 0, 0, 0, 0, 0, 0},
+    {0, 1, 0, 0, 0, 0, 0},
+    {-0.5, 0, 0.866025, 0, 0, 0, 0},
+    {0, 0, 0, 1, 0, 0, 0},
+    {0, 0, 0, 0, 1, 0, 0},
+    {0.01, 0, -0.0519615, 0.73, -0.2, 0.651383, 0},
+    {-0.17, -0.02, 0.21362, -0.14, 0.24, 0.142773, 0.909661},
+};
+
+/**
+ * The square root matrix for <em>NTN Rural NLOS S Band</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-8a and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The square root matrix is dependent on the elevation angle, thus requiring a map.
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const std::map<int, std::vector<std::vector<double>>> sqrtC_NTN_Rural_NLOS_S{
+    {10,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.36, 0.932952, 0, 0, 0, 0},
+         {0.45, 0.516639, 0.728412, 0, 0, 0},
+         {0.02, 0.329277, 0.371881, 0.867687, 0, 0},
+         {-0.06, 0.59853, 0.436258, -0.0324062, 0.668424, 0},
+         {-0.07, 0.0373009, 0.305087, -0.0280496, -0.225204, 0.921481},
+     }},
+    {20,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.39, 0.920815, 0, 0, 0, 0},
+         {0.52, 0.426579, 0.740021, 0, 0, 0},
+         {0, 0.347518, -0.0381664, 0.936896, 0, 0},
+         {-0.04, 0.710675, 0.172483, 0.116993, 0.670748, 0},
+         {-0.17, -0.0394216, 0.115154, 0.243458, -0.0702635, 0.944498},
+     }},
+    {30,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.41, 0.912086, 0, 0, 0, 0},
+         {0.54, 0.49491, 0.680782, 0, 0, 0},
+         {0, 0.350844, -0.152231, 0.923977, 0, 0},
+         {-0.04, 0.694672, 0.0702137, 0.0832998, 0.709903, 0},
+         {-0.19, -0.0854087, 0.0805978, 0.283811, -0.137441, 0.922318},
+     }},
+    {40,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.37, 0.929032, 0, 0, 0, 0},
+         {0.53, 0.480177, 0.698949, 0, 0, 0},
+         {0.01, 0.434538, 0.00864797, 0.900556, 0, 0},
+         {-0.05, 0.765851, -0.0303947, 0.0421641, 0.63896, 0},
+         {-0.17, -0.16458, 0.0989022, 0.158081, -0.150425, 0.941602},
+     }},
+    {50,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.4, 0.916515, 0, 0, 0, 0},
+         {0.55, 0.403703, 0.731111, 0, 0, 0},
+         {0.02, 0.499719, -0.0721341, 0.862947, 0, 0},
+         {-0.06, 0.835775, -0.156481, 0.0373835, 0.521534, 0},
+         {-0.19, -0.301141, 0.145082, 0.144564, -0.0238067, 0.911427},
+     }},
+    {60,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.41, 0.912086, 0, 0, 0, 0},
+         {0.56, 0.339442, 0.755764, 0, 0, 0},
+         {0.02, 0.436582, -0.0256617, 0.899076, 0, 0},
+         {-0.07, 0.856608, -0.12116, 0.0715303, 0.491453, 0},
+         {-0.2, -0.331109, 0.15136, 0.036082, 0.031313, 0.908391},
+     }},
+    {70,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.4, 0.916515, 0, 0, 0, 0},
+         {0.56, 0.386246, 0.732949, 0, 0, 0},
+         {0.04, 0.573913, -0.0601289, 0.815726, 0, 0},
+         {-0.11, 0.813953, -0.0720183, 0.0281118, 0.565158, 0},
+         {-0.19, -0.432071, 0.236423, -0.0247788, -0.0557206, 0.847113},
+     }},
+    {80,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.46, 0.887919, 0, 0, 0, 0},
+         {0.58, 0.469412, 0.665772, 0, 0, 0},
+         {0.01, 0.309262, -0.286842, 0.90663, 0, 0},
+         {-0.05, 0.762457, -0.268721, -0.0467443, 0.584605, 0},
+         {-0.23, -0.580909, 0.399665, 0.0403629, 0.326208, 0.584698},
+     }},
+    {90,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.3, 0.953939, 0, 0, 0, 0},
+         {0.47, 0.81871, 0.329868, 0, 0, 0},
+         {0.06, 0.0712834, -0.595875, 0.797654, 0, 0},
+         {-0.1, 0.408831, -0.0233859, 0.0412736, 0.905873, 0},
+         {-0.13, -0.407783, 0.439436, -0.0768289, -0.212875, 0.756631},
+     }},
+};
+
+/**
+ * The square root matrix for <em>NTN Rural NLOS Ka Band</em>, which is generated
+ * using the Cholesky decomposition according to 3GPP TR 38.811 v15.4.0 table 6.7.2-8b and follows
+ * the order of [SF, K, DS, ASD, ASA, ZSD, ZSA].
+ *
+ * The square root matrix is dependent on the elevation angle, which acts as the corresponding map's
+ * key..
+ *
+ * The Matlab file to generate the matrices can be found in
+ * https://github.com/nyuwireless-unipd/ns3-mmwave/blob/master/src/mmwave/model/BeamFormingMatrix/SqrtMatrix.m
+ */
+static const std::map<int, std::vector<std::vector<double>>> sqrtC_NTN_Rural_NLOS_Ka{
+    {10,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.36, 0.932952, 0, 0, 0, 0},
+         {0.45, 0.527358, 0.72069, 0, 0, 0},
+         {0.02, 0.350715, 0.355282, 0.866241, 0, 0},
+         {-0.07, 0.562515, 0.478504, 0.0162932, 0.670406, 0},
+         {-0.06, 0.0411597, 0.270982, 0.0121094, -0.159927, 0.946336},
+     }},
+    {20,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.38, 0.924986, 0, 0, 0, 0},
+         {0.52, 0.473088, 0.711188, 0, 0, 0},
+         {0, 0.367573, -0.0617198, 0.927944, 0, 0},
+         {-0.04, 0.68628, 0.149228, 0.115257, 0.701332, 0},
+         {-0.16, -0.0441088, 0.118207, 0.251641, -0.0752458, 0.943131},
+     }},
+    {30,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.42, 0.907524, 0, 0, 0, 0},
+         {0.54, 0.48131, 0.690464, 0, 0, 0},
+         {0, 0.363627, -0.137613, 0.921324, 0, 0},
+         {-0.04, 0.686704, 0.117433, 0.104693, 0.708581, 0},
+         {-0.19, -0.0438556, 0.0922685, 0.269877, -0.136292, 0.928469},
+     }},
+    {40,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.36, 0.932952, 0, 0, 0, 0},
+         {0.53, 0.483197, 0.696865, 0, 0, 0},
+         {0.01, 0.464761, -0.0285153, 0.88492, 0, 0},
+         {-0.05, 0.763169, 0.140255, 0.0562856, 0.626286, 0},
+         {-0.16, -0.126051, 0.0942905, 0.195354, -0.217188, 0.92967},
+     }},
+    {50,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.39, 0.920815, 0, 0, 0, 0},
+         {0.55, 0.406705, 0.729446, 0, 0, 0},
+         {0.01, 0.503793, -0.123923, 0.854831, 0, 0},
+         {-0.06, 0.821664, -0.207246, 0.0245302, 0.526988, 0},
+         {-0.19, -0.254231, 0.10679, 0.190931, -0.0665276, 0.920316},
+     }},
+    {60,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.42, 0.907524, 0, 0, 0, 0},
+         {0.56, 0.391395, 0.730213, 0, 0, 0},
+         {0.02, 0.427978, -0.0393147, 0.902712, 0, 0},
+         {-0.06, 0.820694, -0.119986, 0.105509, 0.545281, 0},
+         {-0.2, -0.279882, 0.180145, 0.0563477, -0.0121631, 0.919723},
+     }},
+    {70,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.36, 0.932952, 0, 0, 0, 0},
+         {0.54, 0.519212, 0.662434, 0, 0, 0},
+         {0.04, 0.412025, -0.0234416, 0.909992, 0, 0},
+         {-0.09, 0.758452, -0.0682296, 0.0214276, 0.64151, 0},
+         {-0.17, -0.387158, 0.306169, -0.0291255, -0.109344, 0.845378},
+     }},
+    {80,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.44, 0.897998, 0, 0, 0, 0},
+         {0.57, 0.43519, 0.696928, 0, 0, 0},
+         {0.01, 0.316705, -0.248988, 0.915207, 0, 0},
+         {-0.06, 0.805793, -0.296262, -0.0419182, 0.507514, 0},
+         {-0.22, -0.497551, 0.289742, 0.0785823, 0.328773, 0.711214},
+     }},
+    {90,
+     {
+         {1, 0, 0, 0, 0, 0},
+         {-0.27, 0.96286, 0, 0, 0, 0},
+         {0.46, 0.741748, 0.488067, 0, 0, 0},
+         {0.04, 0.0735309, -0.374828, 0.923308, 0, 0},
+         {-0.08, 0.517624, 0.128779, 0.0795063, 0.838308, 0},
+         {-0.11, -0.321646, 0.0802763, -0.131981, -0.193429, 0.907285},
+     }},
+};
+
+/**
+ * The enumerator used for code clarity when performing parameter assignment in GetThreeGppTable
+ */
+enum Table3gppParams
+{
+    uLgDS,
+    sigLgDS,
+    uLgASD,
+    sigLgASD,
+    uLgASA,
+    sigLgASA,
+    uLgZSA,
+    sigLgZSA,
+    uLgZSD,
+    sigLgZSD,
+    uK,
+    sigK,
+    rTau,
+    uXpr,
+    sigXpr,
+    numOfCluster,
+    raysPerCluster,
+    cDS,
+    cASD,
+    cASA,
+    cZSA,
+    perClusterShadowingStd
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Dense Urban LOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNDenseUrbanLOS{
+    {"S",
+     {
+         {10, {-7.12, 0.8, -3.06, 0.48, 0.94, 0.7,  0.82, 0.03, -2.52, 0.5, 4.4,
+               3.3,   2.5, 24.4,  3.8,  3.0,  20.0, 3.9,  0.0,  11.0,  7.0, 3.0}},
+         {20, {-7.28, 0.67, -2.68, 0.36, 0.87, 0.66, 0.5, 0.09, -2.29, 0.53, 9.0,
+               6.6,   2.5,  23.6,  4.7,  3.0,  20.0, 3.9, 0.0,  11.0,  7.0,  3.0}},
+         {30, {-7.45, 0.68, -2.51, 0.38, 0.92, 0.68, 0.82, 0.05, -2.19, 0.58, 9.3,
+               6.1,   2.5,  23.2,  4.6,  3.0,  20.0, 3.9,  0.0,  11.0,  7.0,  3.0}},
+         {40, {-7.73, 0.66, -2.4, 0.32, 0.79, 0.64, 1.23, 0.03, -2.24, 0.51, 7.9,
+               4.0,   2.5,  22.6, 4.9,  3.0,  20.0, 3.9,  0.0,  11.0,  7.0,  3.0}},
+         {50, {-7.91, 0.62, -2.31, 0.33, 0.72, 0.63, 1.43, 0.06, -2.3, 0.46, 7.4,
+               3.0,   2.5,  21.8,  5.7,  3.0,  20.0, 3.9,  0.0,  11.0, 7.0,  3.0}},
+         {60, {-8.14, 0.51, -2.2, 0.39, 0.6, 0.54, 1.56, 0.05, -2.48, 0.35, 7.0,
+               2.6,   2.5,  20.5, 6.9,  3.0, 20.0, 3.9,  0.0,  11.0,  7.0,  3.0}},
+         {70, {-8.23, 0.45, -2.0, 0.4, 0.55, 0.52, 1.66, 0.05, -2.64, 0.31, 6.9,
+               2.2,   2.5,  19.3, 8.1, 3.0,  20.0, 3.9,  0.0,  11.0,  7.0,  3.0}},
+         {80, {-8.28, 0.31, -1.64, 0.32, 0.71, 0.53, 1.73, 0.02, -2.68, 0.39, 6.5,
+               2.1,   2.5,  17.4,  10.3, 3.0,  20.0, 3.9,  0.0,  11.0,  7.0,  3.0}},
+         {90, {-8.36, 0.08, -0.63, 0.53, 0.81, 0.62, 1.79, 0.01, -2.61, 0.28, 6.8,
+               1.9,   2.5,  12.3,  15.2, 3.0,  20.0, 3.9,  0.0,  11.0,  7.0,  3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-7.43, 0.9, -3.43, 0.54, 0.65, 0.82, 0.82, 0.05, -2.75, 0.55, 6.1,
+               2.6,   2.5, 24.7,  2.1,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {20, {-7.62, 0.78, -3.06, 0.41, 0.53, 0.78, 0.47, 0.11, -2.64, 0.64, 13.7,
+               6.8,   2.5,  24.4,  2.8,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {30, {-7.76, 0.8, -2.91, 0.42, 0.6, 0.83, 0.8, 0.05, -2.49, 0.69, 12.9,
+               6.0,   2.5, 24.4,  2.7,  3.0, 20.0, 1.6, 0.0,  11.0,  7.0,  3.0}},
+         {40, {-8.02, 0.72, -2.81, 0.34, 0.43, 0.78, 1.23, 0.04, -2.51, 0.57, 10.3,
+               3.3,   2.5,  24.2,  2.7,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {50, {-8.13, 0.61, -2.74, 0.34, 0.36, 0.77, 1.42, 0.1, -2.54, 0.5, 9.2,
+               2.2,   2.5,  23.9,  3.1,  3.0,  20.0, 1.6,  0.0, 11.0,  7.0, 3.0}},
+         {60, {-8.3, 0.47, -2.72, 0.7, 0.16, 0.84, 1.56, 0.06, -2.71, 0.37, 8.4,
+               1.9,  2.5,  23.3,  3.9, 3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {70, {-8.34, 0.39, -2.46, 0.4, 0.18, 0.64, 1.65, 0.07, -2.85, 0.31, 8.0,
+               1.5,   2.5,  22.6,  4.8, 3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {80, {-8.39, 0.26, -2.3, 0.78, 0.24, 0.81, 1.73, 0.02, -3.01, 0.45, 7.4,
+               1.6,   2.5,  21.2, 6.8,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {90, {-8.45, 0.01, -1.11, 0.51, 0.36, 0.65, 1.79, 0.01, -3.08, 0.27, 7.6,
+               1.3,   2.5,  17.6,  12.7, 3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Dense Urban NLOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNDenseUrbanNLOS{
+    {"S",
+     {
+         {10, {-6.84, 0.82, -2.08, 0.87, 1.0,  1.6, 1.0, 0.63, -2.08, 0.58,
+               2.3,   23.8, 4.4,   4.0,  20.0, 3.9, 0.0, 15.0, 7.0,   3.0}},
+         {20, {-6.81, 0.61, -1.68, 0.73, 1.44, 0.87, 0.94, 0.65, -1.66, 0.5,
+               2.3,   21.9, 6.3,   4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {30, {-6.94, 0.49, -1.46, 0.53, 1.54, 0.64, 1.15, 0.42, -1.48, 0.4,
+               2.3,   19.7, 8.1,   4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {40, {-7.14, 0.49, -1.43, 0.5, 1.53, 0.56, 1.35, 0.28, -1.46, 0.37,
+               2.3,   18.1, 9.3,   4.0, 20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {50, {-7.34, 0.51, -1.44, 0.58, 1.48, 0.54, 1.44, 0.25, -1.53, 0.47,
+               2.3,   16.3, 11.5,  4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {60, {-7.53, 0.47, -1.33, 0.49, 1.39, 0.68, 1.56, 0.16, -1.61, 0.43,
+               2.3,   14.0, 13.3,  4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {70, {-7.67, 0.44, -1.31, 0.65, 1.42, 0.55, 1.64, 0.18, -1.77, 0.5,
+               2.3,   12.1, 14.9,  4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {80, {-7.82, 0.42, -1.11, 0.69, 1.38, 0.6, 1.7, 0.09, -1.9, 0.42,
+               2.3,   8.7,  17.0,  4.0,  20.0, 3.9, 0.0, 15.0, 7.0,  3.0}},
+         {90, {-7.84, 0.55, -0.11, 0.53, 1.23, 0.6, 1.7, 0.17, -1.99, 0.5,
+               2.3,   6.4,  12.3,  4.0,  20.0, 3.9, 0.0, 15.0, 7.0,   3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-6.86, 0.81, -2.12, 0.94, 1.02, 1.44, 1.01, 0.56, -2.11, 0.59,
+               2.3,   23.7, 4.5,   4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {20, {-6.84, 0.61, -1.74, 0.79, 1.44, 0.77, 0.96, 0.55, -1.69, 0.51,
+               2.3,   21.8, 6.3,   4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {30, {-7.0, 0.56, -1.56, 0.66, 1.48, 0.7, 1.13, 0.43, -1.52, 0.46,
+               2.3,  19.6, 8.2,   4.0,  20.0, 3.9, 0.0,  15.0, 7.0,   3.0}},
+         {40, {-7.21, 0.56, -1.54, 0.63, 1.46, 0.6, 1.3, 0.37, -1.51, 0.43,
+               2.3,   18.0, 9.4,   4.0,  20.0, 3.9, 0.0, 15.0, 7.0,   3.0}},
+         {50, {-7.42, 0.57, -1.45, 0.56, 1.4,  0.59, 1.4, 0.32, -1.54, 0.45,
+               2.3,   16.3, 11.5,  4.0,  20.0, 3.9,  0.0, 15.0, 7.0,   3.0}},
+         {60, {-7.86, 0.55, -1.64, 0.78, 0.97, 1.27, 1.41, 0.45, -1.84, 0.63,
+               2.3,   15.9, 12.4,  4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {70, {-7.76, 0.47, -1.37, 0.56, 1.33, 0.56, 1.63, 0.17, -1.86, 0.51,
+               2.3,   12.3, 15.0,  4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {80, {-8.07, 0.42, -1.29, 0.76, 1.12, 1.04, 1.68, 0.14, -2.16, 0.74,
+               2.3,   10.5, 15.7,  4.0,  20.0, 3.9,  0.0,  15.0, 7.0,   3.0}},
+         {90, {-7.95, 0.59, -0.41, 0.59, 1.04, 0.63, 1.7, 0.17, -2.21, 0.61,
+               2.3,   10.5, 15.7,  4.0,  20.0, 3.9,  0.0, 15.0, 7.0,   3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Urban LOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNUrbanLOS{
+    {"S",
+     {
+         {10, {-7.97, 1.0, -2.6, 0.79, 0.18, 0.74, -0.63, 2.6,  -2.54, 2.62, 31.83,
+               13.84, 2.5, 8.0,  4.0,  4.0,  20.0, 3.9,   0.09, 12.55, 1.25, 3.0}},
+         {20, {-8.12, 0.83, -2.48, 0.8, 0.42, 0.9,  -0.15, 3.31, -2.67, 2.96, 18.78,
+               13.78, 2.5,  8.0,   4.0, 3.0,  20.0, 3.9,   0.09, 12.76, 3.23, 3.0}},
+         {30, {-8.21, 0.68, -2.44, 0.91, 0.41, 1.3,  0.54, 1.1,  -2.03, 0.86, 10.49,
+               10.42, 2.5,  8.0,   4.0,  3.0,  20.0, 3.9,  0.12, 14.36, 4.39, 3.0}},
+         {40, {-8.31, 0.48, -2.6, 1.02, 0.18, 1.69, 0.35, 1.59, -2.28, 1.19, 7.46,
+               8.01,  2.5,  8.0,  4.0,  3.0,  20.0, 3.9,  0.16, 16.42, 5.72, 3.0}},
+         {50, {-8.37, 0.38, -2.71, 1.17, -0.07, 2.04, 0.27, 1.62, -2.48, 1.4,  6.52,
+               8.27,  2.5,  8.0,   4.0,  3.0,   20.0, 3.9,  0.2,  17.13, 6.17, 3.0}},
+         {60, {-8.39, 0.24, -2.76, 1.17, -0.43, 2.54, 0.26, 0.97, -2.56, 0.85, 5.47,
+               7.26,  2.5,  8.0,   4.0,  3.0,   20.0, 3.9,  0.28, 19.01, 7.36, 3.0}},
+         {70, {-8.38, 0.18, -2.78, 1.2, -0.64, 2.47, -0.12, 1.99, -2.96, 1.61, 4.54,
+               5.53,  2.5,  8.0,   4.0, 3.0,   20.0, 3.9,   0.44, 19.31, 7.3,  3.0}},
+         {80, {-8.35, 0.13, -2.65, 1.45, -0.91, 2.69, -0.21, 1.82, -3.08, 1.49, 4.03,
+               4.49,  2.5,  8.0,   4.0,  3.0,   20.0, 3.9,   0.9,  22.39, 7.7,  3.0}},
+         {90, {-8.34, 0.09, -2.27, 1.85, -0.54, 1.66, -0.07, 1.43, -3.0, 1.09, 3.68,
+               3.14,  2.5,  8.0,   4.0,  3.0,   20.0, 3.9,   2.87, 27.8, 9.25, 3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-8.52, 0.92, -3.18, 0.79, -0.4, 0.77, -0.67, 2.22, -2.61, 2.41, 40.18,
+               16.99, 2.5,  8.0,   4.0,  4.0,  20.0, 1.6,   0.09, 11.8,  1.14, 3.0}},
+         {20, {-8.59, 0.79, -3.05, 0.87, -0.15, 0.97, -0.34, 3.04, -2.82, 2.59, 23.62,
+               18.96, 2.5,  8.0,   4.0,  3.0,   20.0, 1.6,   0.09, 11.6,  2.78, 3.0}},
+         {30, {-8.51, 0.65, -2.98, 1.04, -0.18, 1.58, 0.07, 1.33, -2.48, 1.02, 12.48,
+               14.23, 2.5,  8.0,   4.0,  3.0,   20.0, 1.6,  0.11, 13.05, 3.87, 3.0}},
+         {40, {-8.49, 0.48, -3.11, 1.06, -0.31, 1.69, -0.08, 1.45, -2.76, 1.27, 8.56,
+               11.06, 2.5,  8.0,   4.0,  3.0,   20.0, 1.6,   0.15, 14.56, 4.94, 3.0}},
+         {50, {-8.48, 0.46, -3.19, 1.12, -0.58, 2.13, -0.21, 1.62, -2.93, 1.38, 7.42,
+               11.21, 2.5,  8.0,   4.0,  3.0,   20.0, 1.6,   0.18, 15.35, 5.41, 3.0}},
+         {60, {-8.44, 0.34, -3.25, 1.14, -0.9, 2.51, -0.25, 1.06, -3.05, 0.96, 5.97,
+               9.47,  2.5,  8.0,   4.0,  3.0,  20.0, 1.6,   0.27, 16.97, 6.31, 3.0}},
+         {70, {-8.4, 0.27, -3.33, 1.25, -1.16, 2.47, -0.61, 1.88, -3.45, 1.51, 4.88,
+               7.24, 2.5,  8.0,   4.0,  3.0,   20.0, 1.6,   0.42, 17.96, 6.66, 3.0}},
+         {80, {-8.37, 0.19, -3.22, 1.35, -1.48, 2.61, -0.79, 1.87, -3.66, 1.49, 4.22,
+               5.79,  2.5,  8.0,   4.0,  3.0,   20.0, 1.6,   0.86, 20.68, 7.31, 3.0}},
+         {90, {-8.35, 0.14, -2.83, 1.62, -1.14, 1.7,  -0.58, 1.19, -3.56, 0.89, 3.81,
+               4.25,  2.5,  8.0,   4.0,  3.0,   20.0, 1.6,   2.55, 25.08, 9.23, 3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Urban NLOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNUrbanNLOS{
+    {"S",
+     {
+         {10, {-7.24, 1.26, -1.58, 0.89, 0.13, 2.99, -1.13, 2.66, -2.87, 2.76, 0.0,
+               0.0,   2.3,  7.0,   3.0,  3.0,  20.0, 1.6,   0.08, 14.72, 1.57, 3.0}},
+         {20, {-7.7, 0.99, -1.67, 0.89, 0.19, 3.12, 0.49, 2.03, -2.68, 2.76, 0.0,
+               0.0,  2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.1,  14.62, 4.3,  3.0}},
+         {30, {-7.82, 0.86, -1.84, 1.3, 0.44, 2.69, 0.95, 1.54, -2.12, 1.54, 0.0,
+               0.0,   2.3,  7.0,   3.0, 3.0,  20.0, 1.6,  0.14, 16.4,  6.64, 3.0}},
+         {40, {-8.04, 0.75, -2.02, 1.15, 0.48, 2.45, 1.15, 1.02, -2.27, 1.77, 0.0,
+               0.0,   2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.22, 17.86, 9.21, 3.0}},
+         {50, {-8.08, 0.77, -2.06, 1.23, 0.56, 2.17, 1.14, 1.61, -2.5,  2.36,  0.0,
+               0.0,   2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.31, 19.74, 10.32, 3.0}},
+         {60, {-8.1, 0.76, -1.99, 1.02, 0.55, 1.93, 1.13, 1.84, -2.47, 2.33, 0.0,
+               0.0,  2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.49, 19.73, 10.3, 3.0}},
+         {70, {-8.16, 0.73, -2.19, 1.78, 0.48, 1.72, 1.16, 1.81, -2.83, 2.84, 0.0,
+               0.0,   2.3,  7.0,   3.0,  2.0,  20.0, 1.6,  0.97, 20.5,  10.2, 3.0}},
+         {80, {-8.03, 0.79, -1.88, 1.55, 0.53, 1.51, 1.28, 1.35, -2.82, 2.87,  0.0,
+               0.0,   2.3,  7.0,   3.0,  2.0,  20.0, 1.6,  1.52, 26.16, 12.27, 3.0}},
+         {90, {-8.33, 0.7, -2.0, 1.4, 0.32, 1.2,  1.42, 0.6,  -4.55, 4.27,  0.0,
+               0.0,   2.3, 7.0,  3.0, 2.0,  20.0, 1.6,  5.36, 25.83, 12.75, 3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-7.24, 1.26, -1.58, 0.89, 0.13, 2.99, -1.13, 2.66, -2.87, 2.76, 0.0,
+               0.0,   2.3,  7.0,   3.0,  3.0,  20.0, 1.6,   0.08, 14.72, 1.57, 3.0}},
+         {20, {-7.7, 0.99, -1.67, 0.89, 0.19, 3.12, 0.49, 2.03, -2.68, 2.76, 0.0,
+               0.0,  2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.1,  14.62, 4.3,  3.0}},
+         {30, {-7.82, 0.86, -1.84, 1.3, 0.44, 2.69, 0.95, 1.54, -2.12, 1.54, 0.0,
+               0.0,   2.3,  7.0,   3.0, 3.0,  20.0, 1.6,  0.14, 16.4,  6.64, 3.0}},
+         {40, {-8.04, 0.75, -2.02, 1.15, 0.48, 2.45, 1.15, 1.02, -2.27, 1.77, 0.0,
+               0.0,   2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.22, 17.86, 9.21, 3.0}},
+         {50, {-8.08, 0.77, -2.06, 1.23, 0.56, 2.17, 1.14, 1.61, -2.5,  2.36,  0.0,
+               0.0,   2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.31, 19.74, 10.32, 3.0}},
+         {60, {-8.1, 0.76, -1.99, 1.02, 0.55, 1.93, 1.13, 1.84, -2.47, 2.33, 0.0,
+               0.0,  2.3,  7.0,   3.0,  3.0,  20.0, 1.6,  0.49, 19.73, 10.3, 3.0}},
+         {70, {-8.16, 0.73, -2.19, 1.78, 0.48, 1.72, 1.16, 1.81, -2.83, 2.84, 0.0,
+               0.0,   2.3,  7.0,   3.0,  2.0,  20.0, 1.6,  0.97, 20.5,  10.2, 3.0}},
+         {80, {-8.03, 0.79, -1.88, 1.55, 0.53, 1.51, 1.28, 1.35, -2.82, 2.87,  0.0,
+               0.0,   2.3,  7.0,   3.0,  2.0,  20.0, 1.6,  1.52, 26.16, 12.27, 3.0}},
+         {90, {-8.33, 0.7, -2.0, 1.4, 0.32, 1.2,  1.42, 0.6,  -4.55, 4.27,  0.0,
+               0.0,   2.3, 7.0,  3.0, 2.0,  20.0, 1.6,  5.36, 25.83, 12.75, 3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Suburban LOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNSuburbanLOS{
+    {"S",
+     {
+         {10, {-8.16, 0.99, -3.57, 1.62, 0.05, 1.84, -1.78, 0.62, -1.06, 0.96, 11.4,
+               6.26,  2.2,  21.3,  7.6,  3.0,  20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {20, {-8.56, 0.96, -3.8, 1.74, -0.38, 1.94, -1.84, 0.81, -1.21, 0.95, 19.45,
+               10.32, 3.36, 21.0, 8.9,  3.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {30, {-8.72, 0.79, -3.77, 1.72, -0.56, 1.75, -1.67, 0.57, -1.28, 0.49, 20.8,
+               16.34, 3.5,  21.2,  8.5,  3.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {40, {-8.71, 0.81, -3.57, 1.6, -0.59, 1.82, -1.59, 0.86, -1.32, 0.79, 21.2,
+               15.63, 2.81, 21.1,  8.4, 3.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {50, {-8.72, 1.12, -3.42, 1.49, -0.58, 1.87, -1.55, 1.05, -1.39, 0.97, 21.6,
+               14.22, 2.39, 20.7,  9.2,  3.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {60, {-8.66, 1.23, -3.27, 1.43, -0.55, 1.92, -1.51, 1.23, -1.36, 1.17, 19.75,
+               14.19, 2.73, 20.6,  9.8,  3.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {70, {-8.38, 0.55, -3.08, 1.36, -0.28, 1.16, -1.27, 0.54, -1.08, 0.62, 12.0,
+               5.7,   2.07, 20.3,  10.8, 2.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {80, {-8.34, 0.63, -2.75, 1.26, -0.17, 1.09, -1.28, 0.67, -1.31, 0.76, 12.85,
+               9.91,  2.04, 19.8,  12.2, 2.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+         {90, {-8.34, 0.63, -2.75, 1.26, -0.17, 1.09, -1.28, 0.67, -1.31, 0.76, 12.85,
+               9.91,  2.04, 19.1,  13.0, 2.0,   20.0, 1.6,   0.0,  11.0,  7.0,  3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-8.07, 0.46, -3.55, 0.48, 0.89, 0.67, 0.63, 0.35, -3.37, 0.28, 8.9,
+               4.4,   2.5,  23.2,  5.0,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {20, {-8.61, 0.45, -3.69, 0.41, 0.31, 0.78, 0.76, 0.3, -3.28, 0.27, 14.0,
+               4.6,   2.5,  23.6,  4.5,  3.0,  20.0, 1.6,  0.0, 11.0,  7.0,  3.0}},
+         {30, {-8.72, 0.28, -3.59, 0.41, 0.02, 0.75, 1.11, 0.28, -3.04, 0.26, 11.3,
+               3.7,   2.5,  23.5,  4.7,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {40, {-8.63, 0.17, -3.38, 0.35, -0.1, 0.65, 1.37, 0.23, -2.88, 0.21, 9.0,
+               3.5,   2.5,  23.4,  5.2,  3.0,  20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {50, {-8.54, 0.14, -3.23, 0.35, -0.19, 0.55, 1.53, 0.23, -2.83, 0.18, 7.5,
+               3.0,   2.5,  23.2,  5.7,  3.0,   20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {60, {-8.48, 0.15, -3.19, 0.43, -0.54, 0.96, 1.65, 0.17, -2.86, 0.17, 6.6,
+               2.6,   2.5,  23.3,  5.9,  3.0,   20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {70, {-8.42, 0.09, -2.83, 0.33, -0.24, 0.43, 1.74, 0.11, -2.95, 0.1, 5.9,
+               1.7,   2.5,  23.4,  6.2,  2.0,   20.0, 1.6,  0.0,  11.0,  7.0, 3.0}},
+         {80, {-8.39, 0.05, -2.66, 0.44, -0.52, 0.93, 1.82, 0.05, -3.21, 0.07, 5.5,
+               0.7,   2.5,  23.2,  7.0,  2.0,   20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+         {90, {-8.37, 0.02, -1.22, 0.31, -0.15, 0.44, 1.87, 0.02, -3.49, 0.24, 5.4,
+               0.3,   2.5,  23.1,  7.6,  2.0,   20.0, 1.6,  0.0,  11.0,  7.0,  3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Suburban NLOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNSuburbanNLOS{
+    {"S",
+     {
+         {10, {-7.43, 0.5, -2.89, 0.41, 1.49, 0.4,  0.81, 0.36, -3.09, 0.32, 0.0,
+               0.0,   2.3, 22.5,  5.0,  4.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {20, {-7.63, 0.61, -2.76, 0.41, 1.24, 0.82, 1.06, 0.41, -2.93, 0.47, 0.0,
+               0.0,   2.3,  19.4,  8.5,  4.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {30, {-7.86, 0.56, -2.64, 0.41, 1.06, 0.71, 1.12, 0.4, -2.91, 0.46, 0.0,
+               0.0,   2.3,  15.5,  10.0, 4.0,  20.0, 1.6,  0.0, 15.0,  7.0,  3.0}},
+         {40, {-7.96, 0.58, -2.41, 0.52, 0.91, 0.55, 1.14, 0.39, -2.78, 0.54, 0.0,
+               0.0,   2.3,  13.9,  10.6, 4.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {50, {-7.98, 0.59, -2.42, 0.7,  0.98, 0.58, 1.29, 0.35, -2.7, 0.45, 0.0,
+               0.0,   2.3,  11.7,  10.0, 4.0,  20.0, 1.6,  0.0,  15.0, 7.0,  3.0}},
+         {60, {-8.45, 0.47, -2.53, 0.5, 0.49, 1.37, 1.38, 0.36, -3.03, 0.36, 0.0,
+               0.0,   2.3,  9.8,   9.1, 3.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {70, {-8.21, 0.36, -2.35, 0.58, 0.73, 0.49, 1.36, 0.29, -2.9, 0.42, 0.0,
+               0.0,   2.3,  10.3,  9.1,  3.0,  20.0, 1.6,  0.0,  15.0, 7.0,  3.0}},
+         {80, {-8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0,
+               0.0,   2.3,  15.6,  9.1,  3.0,   20.0, 1.6,  0.0, 15.0, 7.0, 3.0}},
+         {90, {-8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0,
+               0.0,   2.3,  15.6,  9.1,  3.0,   20.0, 1.6,  0.0, 15.0, 7.0, 3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-7.43, 0.5, -2.89, 0.41, 1.49, 0.4,  0.81, 0.36, -3.09, 0.32, 0.0,
+               0.0,   2.3, 22.5,  5.0,  4.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {20, {-7.63, 0.61, -2.76, 0.41, 1.24, 0.82, 1.06, 0.41, -2.93, 0.47, 0.0,
+               0.0,   2.3,  19.4,  8.5,  4.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {30, {-7.86, 0.56, -2.64, 0.41, 1.06, 0.71, 1.12, 0.4, -2.91, 0.46, 0.0,
+               0.0,   2.3,  15.5,  10.0, 4.0,  20.0, 1.6,  0.0, 15.0,  7.0,  3.0}},
+         {40, {-7.96, 0.58, -2.41, 0.52, 0.91, 0.55, 1.14, 0.39, -2.78, 0.54, 0.0,
+               0.0,   2.3,  13.9,  10.6, 4.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {50, {-7.98, 0.59, -2.42, 0.7,  0.98, 0.58, 1.29, 0.35, -2.7, 0.45, 0.0,
+               0.0,   2.3,  11.7,  10.0, 4.0,  20.0, 1.6,  0.0,  15.0, 7.0,  3.0}},
+         {60, {-8.45, 0.47, -2.53, 0.5, 0.49, 1.37, 1.38, 0.36, -3.03, 0.36, 0.0,
+               0.0,   2.3,  9.8,   9.1, 3.0,  20.0, 1.6,  0.0,  15.0,  7.0,  3.0}},
+         {70, {-8.21, 0.36, -2.35, 0.58, 0.73, 0.49, 1.36, 0.29, -2.9, 0.42, 0.0,
+               0.0,   2.3,  10.3,  9.1,  3.0,  20.0, 1.6,  0.0,  15.0, 7.0,  3.0}},
+         {80, {-8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0,
+               0.0,   2.3,  15.6,  9.1,  3.0,   20.0, 1.6,  0.0, 15.0, 7.0, 3.0}},
+         {90, {-8.69, 0.29, -2.31, 0.73, -0.04, 1.48, 1.38, 0.2, -3.2, 0.3, 0.0,
+               0.0,   2.3,  15.6,  9.1,  3.0,   20.0, 1.6,  0.0, 15.0, 7.0, 3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Rural LOS scenario.
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNRuralLOS{
+    {"S",
+     {
+         {10, {-9.55, 0.66, -3.42, 0.89, -9.45, 7.83, -4.2, 6.3,  -6.03, 5.19, 24.72,
+               5.07,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,  0.39, 10.81, 1.94, 3.0}},
+         {20, {-8.68, 0.44, -3.0, 0.63, -4.45, 6.86, -2.31, 5.04, -4.31, 4.18, 12.31,
+               5.75,  3.8,  12.0, 4.0,  2.0,   20.0, 0.0,   0.31, 8.09,  1.83, 3.0}},
+         {30, {-8.46, 0.28, -2.86, 0.52, -2.39, 5.14, -0.28, 0.81, -2.57, 0.61, 8.05,
+               5.46,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   0.29, 13.7,  2.28, 3.0}},
+         {40, {-8.36, 0.19, -2.78, 0.45, -1.28, 3.44, -0.38, 1.16, -2.59, 0.79, 6.21,
+               5.23,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   0.37, 20.05, 2.93, 3.0}},
+         {50, {-8.29, 0.14, -2.7, 0.42, -0.99, 2.59, -0.38, 0.82, -2.59, 0.65, 5.04,
+               3.95,  3.8,  12.0, 4.0,  2.0,   20.0, 0.0,   0.61, 24.51, 2.84, 3.0}},
+         {60, {-8.26, 0.1, -2.66, 0.41, -1.05, 2.42, -0.46, 0.67, -2.65, 0.52, 4.42,
+               3.75,  3.8, 12.0,  4.0,  2.0,   20.0, 0.0,   0.9,  26.35, 3.17, 3.0}},
+         {70, {-8.22, 0.1, -2.53, 0.42, -0.9, 1.78, -0.49, 1.0,  -2.69, 0.78, 3.92,
+               2.56,  3.8, 12.0,  4.0,  2.0,  20.0, 0.0,   1.43, 31.84, 3.88, 3.0}},
+         {80, {-8.2, 0.05, -2.21, 0.5, -0.89, 1.65, -0.53, 1.18, -2.65, 1.01, 3.65,
+               1.77, 3.8,  12.0,  4.0, 2.0,   20.0, 0.0,   2.87, 36.62, 4.17, 3.0}},
+         {90, {-8.19, 0.06, -1.78, 0.91, -0.81, 1.26, -0.46, 0.91, -2.65, 0.71, 3.59,
+               1.77,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   5.48, 36.77, 4.29, 3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-9.68, 0.46, -4.03, 0.91, -9.74, 7.52, -5.85, 6.51, -7.45, 5.3,  25.43,
+               7.04,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   0.36, 4.63,  0.75, 3.0}},
+         {20, {-8.86, 0.29, -3.55, 0.7, -4.88, 6.67, -3.27, 5.36, -5.25, 4.42, 12.72,
+               7.47,  3.8,  12.0,  4.0, 2.0,   20.0, 0.0,   0.3,  6.83,  1.25, 3.0}},
+         {30, {-8.59, 0.18, -3.45, 0.55, -2.6, 4.63, -0.88, 0.93, -3.16, 0.68, 8.4,
+               7.18,  3.8,  12.0,  4.0,  2.0,  20.0, 0.0,   0.25, 12.91, 1.93, 3.0}},
+         {40, {-8.46, 0.19, -3.38, 0.52, -1.92, 3.45, -0.93, 0.96, -3.15, 0.73, 6.52,
+               6.88,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   0.35, 18.9,  2.37, 3.0}},
+         {50, {-8.36, 0.14, -3.33, 0.46, -1.56, 2.44, -0.99, 0.97, -3.2,  0.77, 5.24,
+               5.28,  3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   0.53, 22.44, 2.66, 3.0}},
+         {60, {-8.3, 0.15, -3.29, 0.43, -1.66, 2.38, -1.04, 0.83, -3.27, 0.61, 4.57,
+               4.92, 3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   0.88, 25.69, 3.23, 3.0}},
+         {70, {-8.26, 0.13, -3.24, 0.46, -1.59, 1.67, -1.17, 1.01, -3.42, 0.74, 4.02,
+               3.4,   3.8,  12.0,  4.0,  2.0,   20.0, 0.0,   1.39, 27.95, 3.71, 3.0}},
+         {80, {-8.22, 0.03, -2.9, 0.44, -1.58, 1.44, -1.19, 1.01, -3.36, 0.79, 3.7,
+               2.22,  3.8,  12.0, 4.0,  2.0,   20.0, 0.0,   2.7,  31.45, 4.17, 3.0}},
+         {90, {-8.21, 0.07, -2.5, 0.82, -1.51, 1.13, -1.13, 0.85, -3.35, 0.65, 3.62,
+               2.28,  3.8,  12.0, 4.0,  2.0,   20.0, 0.0,   4.97, 28.01, 4.14, 3.0}},
+     }},
+};
+
+/**
+ * The nested map containing the 3GPP value tables for the NTN Rural NLOS scenario
+ * The outer key specifies the band (either "S" or "Ka"), while the inner key represents
+ * the quantized elevation angle.
+ * The inner vector collects the table3gpp values.
+ */
+static const std::map<std::string, std::map<int, std::vector<float>>> NTNRuralNLOS{
+    {"S",
+     {
+         {10, {-9.01, 1.59, -2.9, 1.34, -3.33, 6.22, -0.88, 3.26, -4.92, 3.96, 0.0,
+               0.0,   1.7,  7.0,  3.0,  3.0,   20.0, 0.0,   0.03, 18.16, 2.32, 3.0}},
+         {20, {-8.37, 0.95, -2.5, 1.18, -0.74, 4.22, -0.07, 3.29, -4.06, 4.07, 0.0,
+               0.0,   1.7,  7.0,  3.0,  3.0,   20.0, 0.0,   0.05, 26.82, 7.34, 3.0}},
+         {30, {-8.05, 0.92, -2.12, 1.08, 0.08, 3.02, 0.75, 1.92, -2.33, 1.7,  0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  0.07, 21.99, 8.28, 3.0}},
+         {40, {-7.92, 0.92, -1.99, 1.06, 0.32, 2.45, 0.72, 1.92, -2.24, 2.01, 0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  0.1,  22.86, 8.76, 3.0}},
+         {50, {-7.92, 0.87, -1.9, 1.05, 0.53, 1.63, 0.95, 1.45, -2.24, 2.0,  0.0,
+               0.0,   1.7,  7.0,  3.0,  2.0,  20.0, 0.0,  0.15, 25.93, 9.68, 3.0}},
+         {60, {-7.96, 0.87, -1.85, 1.06, 0.33, 2.08, 0.97, 1.62, -2.22, 1.82, 0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  0.22, 27.79, 9.94, 3.0}},
+         {70, {-7.91, 0.82, -1.69, 1.14, 0.55, 1.58, 1.1, 1.43, -2.19, 1.66, 0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0, 0.5,  28.5,  8.9,  3.0}},
+         {80, {-7.79, 0.86, -1.46, 1.16, 0.45, 2.01, 0.97, 1.88, -2.41, 2.58,  0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  1.04, 37.53, 13.74, 3.0}},
+         {90, {-7.74, 0.81, -1.32, 1.3, 0.4, 2.19, 1.35, 0.62, -2.45, 2.52,  0.0,
+               0.0,   1.7,  7.0,   3.0, 2.0, 20.0, 0.0,  2.11, 29.23, 12.16, 3.0}},
+     }},
+    {"Ka",
+     {
+         {10, {-9.13, 1.91, -2.9, 1.32, -3.4, 6.28, -1.19, 3.81, -5.47, 4.39, 0.0,
+               0.0,   1.7,  7.0,  3.0,  3.0,  20.0, 0.0,   0.03, 18.21, 2.13, 3.0}},
+         {20, {-8.39, 0.94, -2.53, 1.18, -0.51, 3.75, -0.11, 3.33, -4.06, 4.04, 0.0,
+               0.0,   1.7,  7.0,   3.0,  3.0,   20.0, 0.0,   0.05, 24.08, 6.52, 3.0}},
+         {30, {-8.1, 0.92, -2.16, 1.08, 0.06, 2.95, 0.72, 1.93, -2.32, 1.54, 0.0,
+               0.0,  1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  0.07, 22.06, 7.72, 3.0}},
+         {40, {-7.96, 0.94, -2.04, 1.09, 0.2, 2.65, 0.69, 1.91, -2.19, 1.73, 0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0, 20.0, 0.0,  0.09, 21.4,  8.45, 3.0}},
+         {50, {-7.99, 0.89, -1.99, 1.08, 0.4, 1.85, 0.84, 1.7,  -2.16, 1.5,  0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0, 20.0, 0.0,  0.16, 24.26, 8.92, 3.0}},
+         {60, {-8.05, 0.87, -1.95, 1.06, 0.32, 1.83, 0.99, 1.27, -2.24, 1.64, 0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  0.22, 24.15, 8.76, 3.0}},
+         {70, {-8.01, 0.82, -1.81, 1.17, 0.46, 1.57, 0.95, 1.86, -2.29, 1.66, 0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  0.51, 25.99, 9.0,  3.0}},
+         {80, {-8.05, 1.65, -1.56, 1.2, 0.33, 1.99, 0.92, 1.84, -2.65, 2.86, 0.0,
+               0.0,   1.7,  7.0,   3.0, 2.0,  20.0, 0.0,  0.89, 36.07, 13.6, 3.0}},
+         {90, {-7.91, 0.76, -1.53, 1.27, 0.24, 2.18, 1.29, 0.59, -2.23, 1.12,  0.0,
+               0.0,   1.7,  7.0,   3.0,  2.0,  20.0, 0.0,  1.68, 24.51, 10.56, 3.0}},
+     }},
+};
+
 ThreeGppChannelModel::ThreeGppChannelModel()
 {
     NS_LOG_FUNCTION(this);
@@ -291,7 +1121,8 @@
                           MakeDoubleChecker<double>())
             .AddAttribute(
                 "Scenario",
-                "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed)",
+                "The 3GPP scenario (RMa, UMa, UMi-StreetCanyon, InH-OfficeOpen, InH-OfficeMixed, "
+                "NTN-DenseUrban, NTN-Urban, NTN-Suburban, NTN-Rural)",
                 StringValue("UMa"),
                 MakeStringAccessor(&ThreeGppChannelModel::SetScenario,
                                    &ThreeGppChannelModel::GetScenario),
@@ -377,9 +1208,12 @@
     NS_LOG_FUNCTION(this);
     NS_ASSERT_MSG(scenario == "RMa" || scenario == "UMa" || scenario == "UMi-StreetCanyon" ||
                       scenario == "InH-OfficeOpen" || scenario == "InH-OfficeMixed" ||
-                      scenario == "V2V-Urban" || scenario == "V2V-Highway",
+                      scenario == "V2V-Urban" || scenario == "V2V-Highway" ||
+                      scenario == "NTN-DenseUrban" || scenario == "NTN-Urban" ||
+                      scenario == "NTN-Suburban" || scenario == "NTN-Rural",
                   "Unknown scenario, choose between: RMa, UMa, UMi-StreetCanyon, "
-                  "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban or V2V-Highway");
+                  "InH-OfficeOpen, InH-OfficeMixed, V2V-Urban, V2V-Highway, "
+                  "NTN-DenseUrban, NTN-Urban, NTN-Suburban or NTN-Rural");
     m_scenario = scenario;
 }
 
@@ -391,13 +1225,20 @@
 }
 
 Ptr<const ThreeGppChannelModel::ParamsTable>
-ThreeGppChannelModel::GetThreeGppTable(Ptr<const ChannelCondition> channelCondition,
-                                       double hBS,
-                                       double hUT,
-                                       double distance2D) const
+ThreeGppChannelModel::GetThreeGppTable(const Ptr<const MobilityModel> aMob,
+                                       const Ptr<const MobilityModel> bMob,
+                                       Ptr<const ChannelCondition> channelCondition) const
 {
     NS_LOG_FUNCTION(this);
 
+    // NOTE we assume hUT = min (height(a), height(b)) and
+    // hBS = max (height (a), height (b))
+    double hUT = std::min(aMob->GetPosition().z, bMob->GetPosition().z);
+    double hBS = std::max(aMob->GetPosition().z, bMob->GetPosition().z);
+
+    double distance2D = sqrt(pow(aMob->GetPosition().x - bMob->GetPosition().x, 2) +
+                             pow(aMob->GetPosition().y - bMob->GetPosition().y, 2));
+
     double fcGHz = m_frequency / 1.0e9;
     Ptr<ParamsTable> table3gpp = Create<ParamsTable>();
     // table3gpp includes the following parameters:
@@ -1045,6 +1886,538 @@
             NS_FATAL_ERROR("Unknown channel condition");
         }
     }
+    else if (m_scenario.substr(0, 3) == "NTN")
+    {
+        std::string freqBand = (fcGHz < 13) ? "S" : "Ka";
+
+        double elevAngle = 0;
+        bool isSatellite = false; // flag to indicate if one of the two nodes is a satellite
+                                  // if so, parameters will be set accordingly to NOTE 8 of
+                                  // Table 6.7.2 from 3GPP 38.811 V15.4.0 (2020-09)
+
+        Ptr<MobilityModel> aMobNonConst = ConstCast<MobilityModel>(aMob);
+        Ptr<MobilityModel> bMobNonConst = ConstCast<MobilityModel>(bMob);
+
+        if (DynamicCast<GeocentricConstantPositionMobilityModel>(
+                ConstCast<MobilityModel>(aMob)) && // Transform to NS_ASSERT
+            DynamicCast<GeocentricConstantPositionMobilityModel>(
+                ConstCast<MobilityModel>(bMob))) // check if aMob and bMob are of type
+                                                 // GeocentricConstantPositionMobilityModel
+        {
+            Ptr<GeocentricConstantPositionMobilityModel> aNTNMob =
+                DynamicCast<GeocentricConstantPositionMobilityModel>(aMobNonConst);
+            Ptr<GeocentricConstantPositionMobilityModel> bNTNMob =
+                DynamicCast<GeocentricConstantPositionMobilityModel>(bMobNonConst);
+
+            if (aNTNMob->GetGeographicPosition().z <
+                bNTNMob->GetGeographicPosition().z) // b is the HAPS/Satellite
+            {
+                elevAngle = aNTNMob->GetElevationAngle(bNTNMob);
+                if (bNTNMob->GetGeographicPosition().z > 50000)
+                {
+                    isSatellite = true;
+                }
+            }
+            else // a is the HAPS/Satellite
+            {
+                elevAngle = bNTNMob->GetElevationAngle(aNTNMob);
+                if (aNTNMob->GetGeographicPosition().z > 50000)
+                {
+                    isSatellite = true;
+                }
+            }
+        }
+        else
+        {
+            NS_FATAL_ERROR("Mobility Models needs to be of type Geocentric for NTN scenarios");
+        }
+
+        // Round the elevation angle into a two-digits integer between 10 and 90.
+        int elevAngleQuantized = (elevAngle < 10) ? 10 : round(elevAngle / 10) * 10;
+
+        if (m_scenario == "NTN-DenseUrban")
+        {
+            if (channelCondition->IsLos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+
+                // table3gpp->m_uLgASD=-1.79769e+308;  //FOR SATELLITES
+                table3gpp->m_uLgASD =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                // table3gpp->m_sigLgASD=0; //FOR SATELLITES
+                table3gpp->m_sigLgASD =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+
+                table3gpp->m_uLgASA =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+
+                // table3gpp->m_uLgZSD=-1.79769e+308;  //FOR SATELLITES
+                table3gpp->m_uLgZSD =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                // table3gpp->m_sigLgZSD= 0; //FOR SATELLITES
+                table3gpp->m_sigLgZSD =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+
+                table3gpp->m_uK =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster = NTNDenseUrbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNDenseUrbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNDenseUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNDenseUrbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 7; row++)
+                {
+                    for (uint8_t column = 0; column < 7; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] = sqrtC_NTN_DenseUrban_LOS[row][column];
+                    }
+                }
+            }
+            else if (channelCondition->IsNlos())
+            {
+                NS_LOG_UNCOND("Dense Urban NLOS");
+                table3gpp->m_uLgDS =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_rTau =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNDenseUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNDenseUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 6; row++)
+                {
+                    for (uint8_t column = 0; column < 6; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] = sqrtC_NTN_DenseUrban_NLOS[row][column];
+                    }
+                }
+            }
+        }
+        else if (m_scenario == "NTN-Urban")
+        {
+            if (channelCondition->IsLos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_uK =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNUrbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNUrbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNUrbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 7; row++)
+                {
+                    for (uint8_t column = 0; column < 7; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Urban_LOS[row][column];
+                    }
+                }
+            }
+            else if (channelCondition->IsNlos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_uK =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNUrbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNUrbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 6; row++)
+                {
+                    for (uint8_t column = 0; column < 6; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] =
+                            sqrtC_NTN_Urban_NLOS.at(elevAngleQuantized)[row][column];
+                    }
+                }
+            }
+        }
+        else if (m_scenario == "NTN-Suburban")
+        {
+            if (channelCondition->IsLos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_uK =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster = NTNSuburbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNSuburbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNSuburbanLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNSuburbanLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 7; row++)
+                {
+                    for (uint8_t column = 0; column < 7; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Suburban_LOS[row][column];
+                    }
+                }
+            }
+            else if (channelCondition->IsNlos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_uK =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster = NTNSuburbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNSuburbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNSuburbanNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNSuburbanNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 6; row++)
+                {
+                    for (uint8_t column = 0; column < 6; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Suburban_NLOS[row][column];
+                    }
+                }
+            }
+        }
+        else if (m_scenario == "NTN-Rural")
+        {
+            if (channelCondition->IsLos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_uK =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNRuralLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNRuralLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNRuralLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                for (uint8_t row = 0; row < 7; row++)
+                {
+                    for (uint8_t column = 0; column < 7; column++)
+                    {
+                        table3gpp->m_sqrtC[row][column] = sqrtC_NTN_Rural_LOS[row][column];
+                    }
+                }
+            }
+            else if (channelCondition->IsNlos())
+            {
+                table3gpp->m_uLgDS =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgDS];
+                table3gpp->m_sigLgDS =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgDS];
+                table3gpp->m_uLgASD =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASD];
+                table3gpp->m_sigLgASD =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASD];
+                table3gpp->m_uLgASA =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgASA];
+                table3gpp->m_sigLgASA =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgASA];
+                table3gpp->m_uLgZSA =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSA];
+                table3gpp->m_sigLgZSA =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSA];
+                table3gpp->m_uLgZSD =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uLgZSD];
+                table3gpp->m_sigLgZSD =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigLgZSD];
+                table3gpp->m_uK =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uK];
+                table3gpp->m_sigK =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigK];
+                table3gpp->m_rTau =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::rTau];
+                table3gpp->m_uXpr =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::uXpr];
+                table3gpp->m_sigXpr =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::sigXpr];
+                table3gpp->m_numOfCluster =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::numOfCluster];
+                table3gpp->m_raysPerCluster = NTNRuralNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::raysPerCluster];
+                table3gpp->m_cDS =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cDS];
+                table3gpp->m_cASD =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASD];
+                table3gpp->m_cASA =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cASA];
+                table3gpp->m_cZSA =
+                    NTNRuralNLOS.at(freqBand).at(elevAngleQuantized)[Table3gppParams::cZSA];
+                table3gpp->m_perClusterShadowingStd = NTNRuralNLOS.at(freqBand).at(
+                    elevAngleQuantized)[Table3gppParams::perClusterShadowingStd];
+
+                if (freqBand == "S")
+                {
+                    for (uint8_t row = 0; row < 6; row++)
+                    {
+                        for (uint8_t column = 0; column < 6; column++)
+                        {
+                            table3gpp->m_sqrtC[row][column] =
+                                sqrtC_NTN_Rural_NLOS_S.at(elevAngleQuantized)[row][column];
+                        }
+                    }
+                }
+                else if (freqBand == "Ka")
+                {
+                    for (uint8_t row = 0; row < 6; row++)
+                    {
+                        for (uint8_t column = 0; column < 6; column++)
+                        {
+                            table3gpp->m_sqrtC[row][column] =
+                                sqrtC_NTN_Rural_NLOS_Ka.at(elevAngleQuantized)[row][column];
+                        }
+                    }
+                }
+            }
+        }
+        // Parameters that should be set to -inf are instead set to the minimum
+        // value of double
+        if (isSatellite)
+        {
+            table3gpp->m_uLgASD = std::numeric_limits<double>::min();
+            table3gpp->m_sigLgASD = 0;
+            table3gpp->m_uLgZSD = std::numeric_limits<double>::min();
+            table3gpp->m_sigLgZSD = 0;
+        }
+    }
     else
     {
         NS_FATAL_ERROR("unknown scenarios");
@@ -1087,6 +2460,21 @@
     return channelParams->m_generatedTime > channelMatrix->m_generatedTime;
 }
 
+bool
+ThreeGppChannelModel::AntennaSetupChanged(Ptr<const PhasedArrayModel> aAntenna,
+                                          Ptr<const PhasedArrayModel> bAntenna,
+                                          Ptr<const ChannelMatrix> channelMatrix)
+{
+    // This allows changing the number of antenna ports during execution,
+    // which is used by nr's initial association.
+    size_t sAntNumElems = aAntenna->GetNumElems();
+    size_t uAntNumElems = bAntenna->GetNumElems();
+    size_t chanNumRows = channelMatrix->m_channel.GetNumRows();
+    size_t chanNumCols = channelMatrix->m_channel.GetNumCols();
+    return ((uAntNumElems != chanNumRows) || (sAntNumElems != chanNumCols)) &&
+           ((uAntNumElems != chanNumCols) || (sAntNumElems != chanNumRows));
+}
+
 Ptr<const MatrixBasedChannelModel::ChannelMatrix>
 ThreeGppChannelModel::GetChannel(Ptr<const MobilityModel> aMob,
                                  Ptr<const MobilityModel> bMob,
@@ -1126,17 +2514,8 @@
         notFoundParams = true;
     }
 
-    double x = aMob->GetPosition().x - bMob->GetPosition().x;
-    double y = aMob->GetPosition().y - bMob->GetPosition().y;
-    double distance2D = sqrt(x * x + y * y);
-
-    // NOTE we assume hUT = min (height(a), height(b)) and
-    // hBS = max (height (a), height (b))
-    double hUt = std::min(aMob->GetPosition().z, bMob->GetPosition().z);
-    double hBs = std::max(aMob->GetPosition().z, bMob->GetPosition().z);
-
     // get the 3GPP parameters
-    Ptr<const ParamsTable> table3gpp = GetThreeGppTable(condition, hBs, hUt, distance2D);
+    Ptr<const ParamsTable> table3gpp = GetThreeGppTable(aMob, bMob, condition);
 
     if (notFoundParams || updateParams)
     {
@@ -1159,6 +2538,7 @@
         NS_LOG_DEBUG("channel matrix present in the map");
         channelMatrix = m_channelMatrixMap[channelMatrixKey];
         updateMatrix = ChannelMatrixNeedsUpdate(channelParams, channelMatrix);
+        updateMatrix |= AntennaSetupChanged(aAntenna, bAntenna, channelMatrix);
     }
     else
     {
@@ -1391,8 +2771,15 @@
     double cNlos;
     // According to table 7.5-6, only cluster number equals to 8, 10, 11, 12, 19 and 20 is valid.
     // Not sure why the other cases are in Table 7.5-2.
+    // Added case 2 and 3 for the NTN according to table 6.7.2-1aa (28.811)
     switch (table3gpp->m_numOfCluster) // Table 7.5-2
     {
+    case 2:
+        cNlos = 0.501;
+        break;
+    case 3:
+        cNlos = 0.680;
+        break;
     case 4:
         cNlos = 0.779;
         break;
@@ -1438,8 +2825,18 @@
                  1e-4 * pow(kFactor, 3)); //(7.5-10))
     }
 
+    // Added case 2, 3 and 4 for the NTN according to table 6.7.2-1ab (28.811)
     switch (table3gpp->m_numOfCluster) // Table 7.5-4
     {
+    case 2:
+        cNlos = 0.430;
+        break;
+    case 3:
+        cNlos = 0.594;
+        break;
+    case 4:
+        cNlos = 0.697;
+        break;
     case 8:
         cNlos = 0.889;
         break;
@@ -1631,6 +3028,7 @@
         DoubleVector(table3gpp->m_raysPerCluster,
                      0)); // rayZodRadian[n][m], where n is cluster index, m is ray index
 
+    const double pow10_uLgZSD = pow(10, table3gpp->m_uLgZSD);
     for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
     {
         for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
@@ -1640,9 +3038,8 @@
             std::tie(rayAoaRadian[nInd][mInd], rayZoaRadian[nInd][mInd]) =
                 WrapAngles(DegreesToRadians(tempAoa), DegreesToRadians(tempZoa));
 
-            double tempAod = clusterAod[nInd] + table3gpp->m_cASD * offSetAlpha[mInd]; //(7.5-13)
-            double tempZod = clusterZod[nInd] +
-                             0.375 * pow(10, table3gpp->m_uLgZSD) * offSetAlpha[mInd]; //(7.5-20)
+            double tempAod = clusterAod[nInd] + table3gpp->m_cASD * offSetAlpha[mInd];    //(7.5-13)
+            double tempZod = clusterZod[nInd] + 0.375 * pow10_uLgZSD * offSetAlpha[mInd]; //(7.5-20)
             std::tie(rayAodRadian[nInd][mInd], rayZodRadian[nInd][mInd]) =
                 WrapAngles(DegreesToRadians(tempAod), DegreesToRadians(tempZod));
         }
@@ -1664,34 +3061,35 @@
 
     // Step 9: Generate the cross polarization power ratios
     // Step 10: Draw initial phases
-    Double2DVector crossPolarizationPowerRatios; // vector containing the cross polarization power
-                                                 // ratios, as defined by 7.5-21
-    Double3DVector clusterPhase; // rayAoaRadian[n][m], where n is cluster index, m is ray index
+
+    // vector containing the cross polarization power ratios, as defined by 7.5-21
+    auto& crossPolarizationPowerRatios = channelParams->m_crossPolarizationPowerRatios;
+    // rayAoaRadian[n][m], where n is cluster index, m is ray index
+    auto& clusterPhase = channelParams->m_clusterPhase;
+
+    const double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);     // convert to linear
+    const double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0); // convert to linear
+
+    // store the PHI values for all the possible combination of polarization
+    clusterPhase.resize(channelParams->m_reducedClusterNumber);
+    crossPolarizationPowerRatios.resize(channelParams->m_reducedClusterNumber);
     for (uint8_t nInd = 0; nInd < channelParams->m_reducedClusterNumber; nInd++)
     {
-        DoubleVector temp; // used to store the XPR values
-        Double2DVector
-            temp2; // used to store the PHI values for all the possible combination of polarization
+        clusterPhase[nInd].resize(table3gpp->m_raysPerCluster);
+        crossPolarizationPowerRatios[nInd].resize(table3gpp->m_raysPerCluster);
         for (uint8_t mInd = 0; mInd < table3gpp->m_raysPerCluster; mInd++)
         {
-            double uXprLinear = pow(10, table3gpp->m_uXpr / 10.0);     // convert to linear
-            double sigXprLinear = pow(10, table3gpp->m_sigXpr / 10.0); // convert to linear
-
-            temp.push_back(
-                std::pow(10, (m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0));
-            DoubleVector temp3; // used to store the PHI values
+            clusterPhase[nInd][mInd].resize(4);
+            // used to store the XPR values
+            crossPolarizationPowerRatios[nInd][mInd] =
+                std::pow(10, (m_normalRv->GetValue() * sigXprLinear + uXprLinear) / 10.0);
             for (uint8_t pInd = 0; pInd < 4; pInd++)
             {
-                temp3.push_back(m_uniformRv->GetValue(-1 * M_PI, M_PI));
+                // used to store the PHI values
+                clusterPhase[nInd][mInd][pInd] = m_uniformRv->GetValue(-1 * M_PI, M_PI);
             }
-            temp2.push_back(temp3);
         }
-        crossPolarizationPowerRatios.push_back(temp);
-        clusterPhase.push_back(temp2);
     }
-    // store the cluster phase
-    channelParams->m_clusterPhase = clusterPhase;
-    channelParams->m_crossPolarizationPowerRatios = crossPolarizationPowerRatios;
 
     uint8_t cluster1st = 0;
     uint8_t cluster2nd = 0; // first and second strongest cluster;
@@ -1784,6 +3182,20 @@
     channelParams->m_angle.push_back(clusterAod);
     channelParams->m_angle.push_back(clusterZod);
 
+    // Precompute angles sincos
+    channelParams->m_cachedAngleSincos.resize(channelParams->m_angle.size());
+    for (size_t direction = 0; direction < channelParams->m_angle.size(); direction++)
+    {
+        channelParams->m_cachedAngleSincos[direction].resize(
+            channelParams->m_angle[direction].size());
+        for (size_t cluster = 0; cluster < channelParams->m_angle[direction].size(); cluster++)
+        {
+            channelParams->m_cachedAngleSincos[direction][cluster] = {
+                sin(channelParams->m_angle[direction][cluster] * DEG2RAD),
+                cos(channelParams->m_angle[direction][cluster] * DEG2RAD)};
+        }
+    }
+
     // Compute alpha and D as described in 3GPP TR 37.885 v15.3.0, Sec. 6.2.3
     // These terms account for an additional Doppler contribution due to the
     // presence of moving objects in the surrounding environment, such as in
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/three-gpp-channel-model.h ns-3.42/src/spectrum/model/three-gpp-channel-model.h
--- ns-3.41/src/spectrum/model/three-gpp-channel-model.h	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/three-gpp-channel-model.h	2024-05-29 15:29:47.172073600 -0700
@@ -24,6 +24,7 @@
 #include "matrix-based-channel-model.h"
 
 #include "ns3/angles.h"
+#include "ns3/deprecated.h"
 #include <ns3/boolean.h>
 #include <ns3/channel-condition-model.h>
 
@@ -250,11 +251,27 @@
      * \param hUT the height of the UT
      * \param distance2D the 2D distance between tx and rx
      * \return the parameters table
+     * \deprecated Use GetThreeGppTable(const Ptr<const MobilityModel> aMob, const Ptr<const
+     *  MobilityModel> bMob, Ptr<const ChannelCondition> channelCondition) instead
      */
-    virtual Ptr<const ParamsTable> GetThreeGppTable(Ptr<const ChannelCondition> channelCondition,
-                                                    double hBS,
-                                                    double hUT,
-                                                    double distance2D) const;
+    NS_DEPRECATED_3_41("Use GetThreeGppTable(const Ptr<const MobilityModel>, const Ptr<const "
+                       "MobilityModel>, Ptr<const ChannelCondition>) instead")
+    Ptr<const ParamsTable> GetThreeGppTable(Ptr<const ChannelCondition> channelCondition,
+                                            double hBS,
+                                            double hUT,
+                                            double distance2D) const;
+
+    /**
+     * Get the parameters needed to apply the channel generation procedure
+     * \param aMob the mobility model of node A
+     * \param bMob the mobility model of node B
+     * \param channelCondition the channel condition
+     * \return the parameters table
+     */
+    virtual Ptr<const ParamsTable> GetThreeGppTable(
+        const Ptr<const MobilityModel> aMob,
+        const Ptr<const MobilityModel> bMob,
+        Ptr<const ChannelCondition> channelCondition) const;
 
     /**
      * Prepare 3gpp channel parameters among the nodes a and b.
@@ -335,6 +352,18 @@
     bool ChannelMatrixNeedsUpdate(Ptr<const ThreeGppChannelParams> channelParams,
                                   Ptr<const ChannelMatrix> channelMatrix);
 
+    /**
+     * Check if the channel matrix has to be updated due to
+     * changes in the number of antenna ports
+     * \param aAntenna the antenna array of node a
+     * \param bAntenna the antenna array of node b
+     * \param channelMatrix channel matrix structure
+     * \return true if the channel matrix has to be updated, false otherwise
+     */
+    bool AntennaSetupChanged(Ptr<const PhasedArrayModel> aAntenna,
+                             Ptr<const PhasedArrayModel> bAntenna,
+                             Ptr<const ChannelMatrix> channelMatrix);
+
     std::unordered_map<uint64_t, Ptr<ChannelMatrix>>
         m_channelMatrixMap; //!< map containing the channel realizations per pair of
                             //!< PhasedAntennaArray instances, the key of this map is reciprocal
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc ns-3.42/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc
--- ns-3.41/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/three-gpp-spectrum-propagation-loss-model.cc	2024-05-29 15:29:47.172073600 -0700
@@ -175,6 +175,8 @@
     // as described in Section 5.2.2 of 3GPP TR 36.897,
     // and so equal beam weights are used for all the ports.
     // Support of the full-connection model for TXRU virtualization would need extensions.
+    const auto uElemsPerPort = uAnt->GetHElemsPerPort();
+    const auto sElemsPerPort = sAnt->GetHElemsPerPort();
     for (size_t tIndex = 0; tIndex < sPortElems; tIndex++, sIndex++)
     {
         std::complex<double> rxSum(0, 0);
@@ -182,21 +184,21 @@
         for (size_t rIndex = 0; rIndex < uPortElems; rIndex++, uIndex++)
         {
             rxSum += uW[uIndex - startU] * params->m_channel(uIndex, sIndex, cIndex);
-            auto testV = (rIndex % uAnt->GetHElemsPerPort());
-            auto ptInc = uAnt->GetHElemsPerPort() - 1;
+            auto testV = (rIndex % uElemsPerPort);
+            auto ptInc = uElemsPerPort - 1;
             if (testV == ptInc)
             {
-                auto incVal = uAnt->GetNumColumns() - uAnt->GetHElemsPerPort();
+                auto incVal = uAnt->GetNumColumns() - uElemsPerPort;
                 uIndex += incVal; // Increment by a factor to reach next column in a port
             }
         }
 
         txSum += sW[sIndex - startS] * rxSum;
-        auto testV = (tIndex % sAnt->GetHElemsPerPort());
-        auto ptInc = sAnt->GetHElemsPerPort() - 1;
+        auto testV = (tIndex % sElemsPerPort);
+        auto ptInc = sElemsPerPort - 1;
         if (testV == ptInc)
         {
-            size_t incVal = sAnt->GetNumColumns() - sAnt->GetHElemsPerPort();
+            size_t incVal = sAnt->GetNumColumns() - sElemsPerPort;
             sIndex += incVal; // Increment by a factor to reach next column in a port
         }
     }
@@ -237,31 +239,19 @@
     NS_ASSERT(numCluster <= longTerm->GetNumPages());
 
     // check if channelParams structure is generated in direction s-to-u or u-to-s
-    bool isSameDirection = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
-
-    MatrixBasedChannelModel::DoubleVector zoa;
-    MatrixBasedChannelModel::DoubleVector zod;
-    MatrixBasedChannelModel::DoubleVector aoa;
-    MatrixBasedChannelModel::DoubleVector aod;
+    bool isSameDir = (channelParams->m_nodeIds == channelMatrix->m_nodeIds);
 
     // if channel params is generated in the same direction in which we
     // generate the channel matrix, angles and zenith of departure and arrival are ok,
     // just set them to corresponding variable that will be used for the generation
     // of channel matrix, otherwise we need to flip angles and zeniths of departure and arrival
-    if (isSameDirection)
-    {
-        zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
-        zod = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
-        aoa = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
-        aod = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
-    }
-    else
-    {
-        zod = channelParams->m_angle[MatrixBasedChannelModel::ZOA_INDEX];
-        zoa = channelParams->m_angle[MatrixBasedChannelModel::ZOD_INDEX];
-        aod = channelParams->m_angle[MatrixBasedChannelModel::AOA_INDEX];
-        aoa = channelParams->m_angle[MatrixBasedChannelModel::AOD_INDEX];
-    }
+    using DPV = std::vector<std::pair<double, double>>;
+    using MBCM = MatrixBasedChannelModel;
+    const auto& cachedAngleSincos = channelParams->m_cachedAngleSincos;
+    const DPV& zoa = cachedAngleSincos[isSameDir ? MBCM::ZOA_INDEX : MBCM::ZOD_INDEX];
+    const DPV& zod = cachedAngleSincos[isSameDir ? MBCM::ZOD_INDEX : MBCM::ZOA_INDEX];
+    const DPV& aoa = cachedAngleSincos[isSameDir ? MBCM::AOA_INDEX : MBCM::AOD_INDEX];
+    const DPV& aod = cachedAngleSincos[isSameDir ? MBCM::AOD_INDEX : MBCM::AOA_INDEX];
 
     for (size_t cIndex = 0; cIndex < numCluster; cIndex++)
     {
@@ -281,13 +271,12 @@
 
         // cluster angle angle[direction][n], where direction = 0(aoa), 1(zoa).
         double tempDoppler =
-            factor * ((sin(zoa[cIndex] * M_PI / 180) * cos(aoa[cIndex] * M_PI / 180) * uSpeed.x +
-                       sin(zoa[cIndex] * M_PI / 180) * sin(aoa[cIndex] * M_PI / 180) * uSpeed.y +
-                       cos(zoa[cIndex] * M_PI / 180) * uSpeed.z) +
-                      (sin(zod[cIndex] * M_PI / 180) * cos(aod[cIndex] * M_PI / 180) * sSpeed.x +
-                       sin(zod[cIndex] * M_PI / 180) * sin(aod[cIndex] * M_PI / 180) * sSpeed.y +
-                       cos(zod[cIndex] * M_PI / 180) * sSpeed.z) +
-                      2 * alpha * D);
+            factor *
+            ((zoa[cIndex].first * aoa[cIndex].second * uSpeed.x +
+              zoa[cIndex].first * aoa[cIndex].first * uSpeed.y + zoa[cIndex].second * uSpeed.z) +
+             (zod[cIndex].first * aod[cIndex].second * sSpeed.x +
+              zod[cIndex].first * aod[cIndex].first * sSpeed.y + zod[cIndex].second * sSpeed.z) +
+             2 * alpha * D);
         doppler[cIndex] = std::complex<double>(cos(tempDoppler), sin(tempDoppler));
     }
 
@@ -368,40 +357,70 @@
     Ptr<MatrixBasedChannelModel::Complex3DVector> chanSpct =
         Create<MatrixBasedChannelModel::Complex3DVector>(numRxPorts, numTxPorts, (uint16_t)numRb);
 
+    // Precompute the delay until numRb, numCluster or RB width changes
+    // Whenever the channelParams is updated, the number of numRbs, numClusters
+    // and RB width (12*SCS) are reset, ensuring these values are updated too
+    double rbWidth = inPsd->ConstBandsBegin()->fh - inPsd->ConstBandsBegin()->fl;
+
+    if (channelParams->m_cachedDelaySincos.GetNumRows() != numRb ||
+        channelParams->m_cachedDelaySincos.GetNumCols() != numCluster ||
+        channelParams->m_cachedRbWidth != rbWidth)
+    {
+        channelParams->m_cachedRbWidth = rbWidth;
+        channelParams->m_cachedDelaySincos = ComplexMatrixArray(numRb, numCluster);
+        auto sbit = inPsd->ConstBandsBegin(); // band iterator
+        for (unsigned i = 0; i < numRb; i++)
+        {
+            double fsb = (*sbit).fc; // center frequency of the sub-band
+            for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
+            {
+                double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
+                channelParams->m_cachedDelaySincos(i, cIndex) =
+                    std::complex<double>(cos(delay), sin(delay));
+            }
+            sbit++;
+        }
+    }
+
+    // Compute the product between the doppler and the delay sincos
+    auto delaySincosCopy = channelParams->m_cachedDelaySincos;
+    for (size_t iRb = 0; iRb < inPsd->GetValuesN(); iRb++)
+    {
+        for (std::size_t cIndex = 0; cIndex < numCluster; cIndex++)
+        {
+            delaySincosCopy(iRb, cIndex) *= doppler[cIndex];
+        }
+    }
+
     // If "params" (ChannelMatrix) and longTerm were computed for the reverse direction (e.g. this
     // is a DL transmission but params and longTerm were last updated during UL), then the elements
     // in longTerm start from different offsets.
 
-    auto vit = inPsd->ValuesBegin();      // psd iterator
-    auto sbit = inPsd->ConstBandsBegin(); // band iterator
+    auto vit = inPsd->ValuesBegin(); // psd iterator
     size_t iRb = 0;
     // Compute the frequency-domain channel matrix
     while (vit != inPsd->ValuesEnd())
     {
         if ((*vit) != 0.00)
         {
-            double fsb = (*sbit).fc; // center frequency of the sub-band
+            auto sqrtVit = sqrt(*vit);
             for (auto rxPortIdx = 0; rxPortIdx < numRxPorts; rxPortIdx++)
             {
                 for (auto txPortIdx = 0; txPortIdx < numTxPorts; txPortIdx++)
                 {
                     std::complex<double> subsbandGain(0.0, 0.0);
-
                     for (size_t cIndex = 0; cIndex < numCluster; cIndex++)
                     {
-                        double delay = -2 * M_PI * fsb * (channelParams->m_delay[cIndex]);
                         subsbandGain += directionalLongTerm(rxPortIdx, txPortIdx, cIndex) *
-                                        doppler[cIndex] *
-                                        std::complex<double>(cos(delay), sin(delay));
+                                        delaySincosCopy(iRb, cIndex);
                     }
                     // Multiply with the square root of the input PSD so that the norm (absolute
                     // value squared) of chanSpct will be the output PSD
-                    chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrt(*vit) * subsbandGain;
+                    chanSpct->Elem(rxPortIdx, txPortIdx, iRb) = sqrtVit * subsbandGain;
                 }
             }
         }
         vit++;
-        sbit++;
         iRb++;
     }
     return chanSpct;
@@ -492,10 +511,6 @@
     NS_LOG_FUNCTION(this << spectrumSignalParams << a << b << aPhasedArrayModel
                          << bPhasedArrayModel);
 
-    if (a->GetPosition() == b->GetPosition())
-    {
-        return spectrumSignalParams->Copy();
-    }
     uint32_t aId = a->GetObject<Node>()->GetId(); // id of the node a
     uint32_t bId = b->GetObject<Node>()->GetId(); // id of the node b
     NS_ASSERT_MSG(aPhasedArrayModel, "Antenna not found for node " << aId);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/tv-spectrum-transmitter.cc ns-3.42/src/spectrum/model/tv-spectrum-transmitter.cc
--- ns-3.41/src/spectrum/model/tv-spectrum-transmitter.cc	2024-02-09 14:44:08.497794400 -0800
+++ ns-3.42/src/spectrum/model/tv-spectrum-transmitter.cc	2024-05-29 15:29:47.172073600 -0700
@@ -507,8 +507,6 @@
             case 82:
             case 83:
             case 84:
-                (*psd)[i] = 3.16228e-06 * basePsdWattsHz;
-                break;
             case 85:
             case 86:
             case 87:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/waveform-generator.cc ns-3.42/src/spectrum/model/waveform-generator.cc
--- ns-3.41/src/spectrum/model/waveform-generator.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/model/waveform-generator.cc	2024-05-29 15:29:47.172073600 -0700
@@ -53,7 +53,7 @@
     m_channel = nullptr;
     m_netDevice = nullptr;
     m_mobility = nullptr;
-    if (m_nextWave.IsRunning())
+    if (m_nextWave.IsPending())
     {
         m_nextWave.Cancel();
     }
@@ -202,7 +202,7 @@
 WaveformGenerator::Start()
 {
     NS_LOG_FUNCTION(this);
-    if (!m_nextWave.IsRunning())
+    if (!m_nextWave.IsPending())
     {
         NS_LOG_LOGIC("generator was not active, now starting");
         m_startTime = Now();
@@ -214,7 +214,7 @@
 WaveformGenerator::Stop()
 {
     NS_LOG_FUNCTION(this);
-    if (m_nextWave.IsRunning())
+    if (m_nextWave.IsPending())
     {
         m_nextWave.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/wifi-spectrum-value-helper.cc ns-3.42/src/spectrum/model/wifi-spectrum-value-helper.cc
--- ns-3.41/src/spectrum/model/wifi-spectrum-value-helper.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/model/wifi-spectrum-value-helper.cc	1969-12-31 16:00:00.000000000 -0800
@@ -1,830 +0,0 @@
-/*
- * Copyright (c) 2009 CTTC
- * Copyright (c) 2010 TELEMATICS LAB, DEE - Politecnico di Bari
- * Copyright (c) 2017 Orange Labs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Authors: Nicola Baldo <nbaldo@cttc.es>
- *          Giuseppe Piro  <g.piro@poliba.it>
- *          Rediet <getachew.redieteab@orange.com>
- */
-
-#include "wifi-spectrum-value-helper.h"
-
-#include "ns3/assert.h"
-#include "ns3/fatal-error.h"
-#include "ns3/log.h"
-
-#include <cmath>
-#include <map>
-#include <sstream>
-
-namespace ns3
-{
-
-NS_LOG_COMPONENT_DEFINE("WifiSpectrumValueHelper");
-
-///< Wifi Spectrum Model structure
-struct WifiSpectrumModelId
-{
-    uint32_t m_centerFrequency; ///< center frequency (in MHz)
-    uint16_t m_channelWidth;    ///< channel width (in MHz)
-    uint32_t m_carrierSpacing;  ///< carrier spacing (in Hz)
-    uint16_t m_guardBandwidth;  ///< guard band width (in MHz)
-};
-
-/**
- * Less than operator
- * \param a the first wifi spectrum to compare
- * \param b the second wifi spectrum to compare
- * \returns true if the first spectrum is less than the second spectrum
- */
-bool
-operator<(const WifiSpectrumModelId& a, const WifiSpectrumModelId& b)
-{
-    return (
-        (a.m_centerFrequency < b.m_centerFrequency) ||
-        ((a.m_centerFrequency == b.m_centerFrequency) && (a.m_channelWidth < b.m_channelWidth)) ||
-        ((a.m_centerFrequency == b.m_centerFrequency) && (a.m_channelWidth == b.m_channelWidth) &&
-         (a.m_carrierSpacing < b.m_carrierSpacing)) // to cover coexistence of 11ax with legacy case
-        || ((a.m_centerFrequency == b.m_centerFrequency) &&
-            (a.m_channelWidth == b.m_channelWidth) && (a.m_carrierSpacing == b.m_carrierSpacing) &&
-            (a.m_guardBandwidth <
-             b.m_guardBandwidth))); // to cover 2.4 GHz case, where DSSS coexists with OFDM
-}
-
-static std::map<WifiSpectrumModelId, Ptr<SpectrumModel>>
-    g_wifiSpectrumModelMap; ///< static initializer for the class
-
-Ptr<SpectrumModel>
-WifiSpectrumValueHelper::GetSpectrumModel(uint32_t centerFrequency,
-                                          uint16_t channelWidth,
-                                          uint32_t carrierSpacing,
-                                          uint16_t guardBandwidth)
-{
-    NS_LOG_FUNCTION(centerFrequency << channelWidth << carrierSpacing << guardBandwidth);
-    Ptr<SpectrumModel> ret;
-    WifiSpectrumModelId key{centerFrequency, channelWidth, carrierSpacing, guardBandwidth};
-    auto it = g_wifiSpectrumModelMap.find(key);
-    if (it != g_wifiSpectrumModelMap.end())
-    {
-        ret = it->second;
-    }
-    else
-    {
-        Bands bands;
-        double centerFrequencyHz = centerFrequency * 1e6;
-        double bandwidth = (channelWidth + (2.0 * guardBandwidth)) * 1e6;
-        // For OFDM, the center subcarrier is null (at center frequency)
-        auto numBands = static_cast<uint32_t>((bandwidth / carrierSpacing) + 0.5);
-        NS_ASSERT(numBands > 0);
-        if (numBands % 2 == 0)
-        {
-            // round up to the nearest odd number of subbands so that bands
-            // are symmetric around center frequency
-            numBands += 1;
-        }
-        NS_ASSERT_MSG(numBands % 2 == 1, "Number of bands should be odd");
-        NS_LOG_DEBUG("Num bands " << numBands << " band bandwidth " << carrierSpacing);
-        // lay down numBands/2 bands symmetrically around center frequency
-        // and place an additional band at center frequency
-        double startingFrequencyHz =
-            centerFrequencyHz - (numBands / 2 * carrierSpacing) - carrierSpacing / 2;
-        for (size_t i = 0; i < numBands; i++)
-        {
-            BandInfo info;
-            double f = startingFrequencyHz + (i * carrierSpacing);
-            info.fl = f;
-            f += carrierSpacing / 2;
-            info.fc = f;
-            f += carrierSpacing / 2;
-            info.fh = f;
-            NS_LOG_DEBUG("creating band " << i << " (" << info.fl << ":" << info.fc << ":"
-                                          << info.fh << ")");
-            bands.push_back(info);
-        }
-        ret = Create<SpectrumModel>(std::move(bands));
-        g_wifiSpectrumModelMap.insert(std::pair<WifiSpectrumModelId, Ptr<SpectrumModel>>(key, ret));
-    }
-    NS_LOG_LOGIC("returning SpectrumModel::GetUid () == " << ret->GetUid());
-    return ret;
-}
-
-// Power allocated to 71 center subbands out of 135 total subbands in the band
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateDsssTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                          double txPowerW,
-                                                          uint16_t guardBandwidth)
-{
-    NS_LOG_FUNCTION(centerFrequency << txPowerW << +guardBandwidth);
-    uint16_t channelWidth = 22; // DSSS channels are 22 MHz wide
-    uint32_t carrierSpacing = 312500;
-    Ptr<SpectrumValue> c = Create<SpectrumValue>(
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    auto vit = c->ValuesBegin();
-    auto bit = c->ConstBandsBegin();
-    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
-    NS_ASSERT(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1));
-    // Evenly spread power across 22 MHz
-    double txPowerPerBand = txPowerW / nAllocatedBands;
-    for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++, bit++)
-    {
-        if ((i >= (nGuardBands / 2)) && (i <= ((nGuardBands / 2) + nAllocatedBands - 1)))
-        {
-            *vit = txPowerPerBand / (bit->fh - bit->fl);
-        }
-    }
-    return c;
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                          uint16_t channelWidth,
-                                                          double txPowerW,
-                                                          uint16_t guardBandwidth,
-                                                          double minInnerBandDbr,
-                                                          double minOuterBandDbr,
-                                                          double lowestPointDbr)
-{
-    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
-                                    << minOuterBandDbr << lowestPointDbr);
-    uint32_t carrierSpacing = 0;
-    uint32_t innerSlopeWidth = 0;
-    switch (channelWidth)
-    {
-    case 20:
-        carrierSpacing = 312500;
-        innerSlopeWidth = static_cast<uint32_t>((2e6 / carrierSpacing) + 0.5); // [-11;-9] & [9;11]
-        break;
-    case 10:
-        carrierSpacing = 156250;
-        innerSlopeWidth =
-            static_cast<uint32_t>((1e6 / carrierSpacing) + 0.5); // [-5.5;-4.5] & [4.5;5.5]
-        break;
-    case 5:
-        carrierSpacing = 78125;
-        innerSlopeWidth =
-            static_cast<uint32_t>((5e5 / carrierSpacing) + 0.5); // [-2.75;-2.5] & [2.5;2.75]
-        break;
-    default:
-        NS_FATAL_ERROR("Channel width " << channelWidth << " should be correctly set.");
-        return nullptr;
-    }
-
-    Ptr<SpectrumValue> c = Create<SpectrumValue>(
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
-    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
-                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
-    // 52 subcarriers (48 data + 4 pilot)
-    // skip guard band and 6 subbands, then place power in 26 subbands, then
-    // skip the center subband, then place power in 26 subbands, then skip
-    // the final 6 subbands and the guard band.
-    double txPowerPerBandW = txPowerW / 52;
-    NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
-    uint32_t start1 = (nGuardBands / 2) + 6;
-    uint32_t stop1 = start1 + 26 - 1;
-    uint32_t start2 = stop1 + 2;
-    uint32_t stop2 = start2 + 26 - 1;
-
-    // Build transmit spectrum mask
-    std::vector<WifiSpectrumBandIndices> subBands{
-        std::make_pair(start1, stop1),
-        std::make_pair(start2, stop2),
-    };
-    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
-    CreateSpectrumMaskForOfdm(c,
-                              subBands,
-                              maskBand,
-                              txPowerPerBandW,
-                              nGuardBands,
-                              innerSlopeWidth,
-                              minInnerBandDbr,
-                              minOuterBandDbr,
-                              lowestPointDbr);
-    NormalizeSpectrumMask(c, txPowerW);
-    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
-    return c;
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateDuplicated20MhzTxPowerSpectralDensity(
-    uint32_t centerFrequency,
-    uint16_t channelWidth,
-    double txPowerW,
-    uint16_t guardBandwidth,
-    double minInnerBandDbr,
-    double minOuterBandDbr,
-    double lowestPointDbr,
-    const std::vector<bool>& puncturedSubchannels)
-{
-    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
-                                    << minOuterBandDbr << lowestPointDbr);
-    uint32_t carrierSpacing = 312500;
-    Ptr<SpectrumValue> c = Create<SpectrumValue>(
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
-    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
-                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
-    std::size_t num20MhzBands = channelWidth / 20;
-    std::size_t numAllocatedSubcarriersPer20MHz = 52;
-    NS_ASSERT(puncturedSubchannels.empty() || (puncturedSubchannels.size() == num20MhzBands));
-    double txPowerPerBandW = (txPowerW / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
-    NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
-
-    std::size_t numSubcarriersPer20MHz = (20 * 1e6) / carrierSpacing;
-    std::size_t numUnallocatedSubcarriersPer20MHz =
-        numSubcarriersPer20MHz - numAllocatedSubcarriersPer20MHz;
-    std::vector<WifiSpectrumBandIndices>
-        subBands; // list of data/pilot-containing subBands (sent at 0dBr)
-    subBands.resize(num20MhzBands *
-                    2); // the center subcarrier is skipped, hence 2 subbands per 20 MHz subchannel
-    uint32_t start = (nGuardBands / 2) + (numUnallocatedSubcarriersPer20MHz / 2);
-    uint32_t stop;
-    uint8_t index = 0;
-    for (auto it = subBands.begin(); it != subBands.end();)
-    {
-        if (!puncturedSubchannels.empty() && puncturedSubchannels.at(index++))
-        {
-            // if subchannel is punctured, skip it and go the next one
-            NS_LOG_DEBUG("20 MHz subchannel " << +index << " is punctured");
-            it += 2;
-            continue;
-        }
-        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
-        *it = std::make_pair(start, stop);
-        ++it;
-        start = stop + 2; // skip center subcarrier
-        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
-        *it = std::make_pair(start, stop);
-        ++it;
-        start = stop + numUnallocatedSubcarriersPer20MHz;
-    }
-
-    // Prepare spectrum mask specific variables
-    auto innerSlopeWidth = static_cast<uint32_t>(
-        (2e6 / carrierSpacing) +
-        0.5); // size in number of subcarriers of the 0dBr<->20dBr slope (2MHz for HT/VHT)
-    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
-
-    // Build transmit spectrum mask
-    CreateSpectrumMaskForOfdm(c,
-                              subBands,
-                              maskBand,
-                              txPowerPerBandW,
-                              nGuardBands,
-                              innerSlopeWidth,
-                              minInnerBandDbr,
-                              minOuterBandDbr,
-                              lowestPointDbr);
-    NormalizeSpectrumMask(c, txPowerW);
-    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
-    return c;
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateHtOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                            uint16_t channelWidth,
-                                                            double txPowerW,
-                                                            uint16_t guardBandwidth,
-                                                            double minInnerBandDbr,
-                                                            double minOuterBandDbr,
-                                                            double lowestPointDbr)
-{
-    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
-                                    << minOuterBandDbr << lowestPointDbr);
-    uint32_t carrierSpacing = 312500;
-    Ptr<SpectrumValue> c = Create<SpectrumValue>(
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
-    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
-                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
-    std::size_t num20MhzBands = channelWidth / 20;
-    std::size_t numAllocatedSubcarriersPer20MHz = 56;
-    double txPowerPerBandW = (txPowerW / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
-    NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
-
-    std::size_t numSubcarriersPer20MHz = (20 * 1e6) / carrierSpacing;
-    std::size_t numUnallocatedSubcarriersPer20MHz =
-        numSubcarriersPer20MHz - numAllocatedSubcarriersPer20MHz;
-    std::vector<WifiSpectrumBandIndices>
-        subBands; // list of data/pilot-containing subBands (sent at 0dBr)
-    subBands.resize(num20MhzBands *
-                    2); // the center subcarrier is skipped, hence 2 subbands per 20 MHz subchannel
-    uint32_t start = (nGuardBands / 2) + (numUnallocatedSubcarriersPer20MHz / 2);
-    uint32_t stop;
-    for (auto it = subBands.begin(); it != subBands.end();)
-    {
-        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
-        *it = std::make_pair(start, stop);
-        ++it;
-        start = stop + 2; // skip center subcarrier
-        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
-        *it = std::make_pair(start, stop);
-        ++it;
-        start = stop + numUnallocatedSubcarriersPer20MHz;
-    }
-
-    // Prepare spectrum mask specific variables
-    auto innerSlopeWidth = static_cast<uint32_t>(
-        (2e6 / carrierSpacing) +
-        0.5); // size in number of subcarriers of the inner band (2MHz for HT/VHT)
-    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
-
-    // Build transmit spectrum mask
-    CreateSpectrumMaskForOfdm(c,
-                              subBands,
-                              maskBand,
-                              txPowerPerBandW,
-                              nGuardBands,
-                              innerSlopeWidth,
-                              minInnerBandDbr,
-                              minOuterBandDbr,
-                              lowestPointDbr);
-    NormalizeSpectrumMask(c, txPowerW);
-    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
-    return c;
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateHeOfdmTxPowerSpectralDensity(
-    uint32_t centerFrequency,
-    uint16_t channelWidth,
-    double txPowerW,
-    uint16_t guardBandwidth,
-    double minInnerBandDbr,
-    double minOuterBandDbr,
-    double lowestPointDbr,
-    const std::vector<bool>& puncturedSubchannels)
-{
-    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
-                                    << minOuterBandDbr << lowestPointDbr);
-    uint32_t carrierSpacing = 78125;
-    Ptr<SpectrumValue> c = Create<SpectrumValue>(
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
-    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
-    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
-                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
-    double txPowerPerBandW = 0.0;
-    uint32_t start1;
-    uint32_t stop1;
-    uint32_t start2;
-    uint32_t stop2;
-    uint32_t start3;
-    uint32_t stop3;
-    uint32_t start4;
-    uint32_t stop4;
-    // Prepare spectrum mask specific variables
-    auto innerSlopeWidth = static_cast<uint32_t>(
-        (1e6 / carrierSpacing) + 0.5); // size in number of subcarriers of the inner band
-    std::vector<WifiSpectrumBandIndices>
-        subBands; // list of data/pilot-containing subBands (sent at 0dBr)
-    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
-    switch (channelWidth)
-    {
-    case 20:
-        // 242 subcarriers (234 data + 8 pilot)
-        txPowerPerBandW = txPowerW / 242;
-        innerSlopeWidth =
-            static_cast<uint32_t>((5e5 / carrierSpacing) + 0.5); // [-10.25;-9.75] & [9.75;10.25]
-        // skip the guard band and 6 subbands, then place power in 121 subbands, then
-        // skip 3 DC, then place power in 121 subbands, then skip
-        // the final 5 subbands and the guard band.
-        start1 = (nGuardBands / 2) + 6;
-        stop1 = start1 + 121 - 1;
-        start2 = stop1 + 4;
-        stop2 = start2 + 121 - 1;
-        subBands.emplace_back(start1, stop1);
-        subBands.emplace_back(start2, stop2);
-        break;
-    case 40:
-        // 484 subcarriers (468 data + 16 pilot)
-        txPowerPerBandW = txPowerW / 484;
-        // skip the guard band and 12 subbands, then place power in 242 subbands, then
-        // skip 5 DC, then place power in 242 subbands, then skip
-        // the final 11 subbands and the guard band.
-        start1 = (nGuardBands / 2) + 12;
-        stop1 = start1 + 242 - 1;
-        start2 = stop1 + 6;
-        stop2 = start2 + 242 - 1;
-        subBands.emplace_back(start1, stop1);
-        subBands.emplace_back(start2, stop2);
-        break;
-    case 80:
-        // 996 subcarriers (980 data + 16 pilot)
-        txPowerPerBandW = txPowerW / 996;
-        // skip the guard band and 12 subbands, then place power in 498 subbands, then
-        // skip 5 DC, then place power in 498 subbands, then skip
-        // the final 11 subbands and the guard band.
-        start1 = (nGuardBands / 2) + 12;
-        stop1 = start1 + 498 - 1;
-        start2 = stop1 + 6;
-        stop2 = start2 + 498 - 1;
-        subBands.emplace_back(start1, stop1);
-        subBands.emplace_back(start2, stop2);
-        break;
-    case 160:
-        // 2 x 996 subcarriers (2 x 80 MHZ bands)
-        txPowerPerBandW = txPowerW / (2 * 996);
-        start1 = (nGuardBands / 2) + 12;
-        stop1 = start1 + 498 - 1;
-        start2 = stop1 + 6;
-        stop2 = start2 + 498 - 1;
-        start3 = stop2 + (2 * 12);
-        stop3 = start3 + 498 - 1;
-        start4 = stop3 + 6;
-        stop4 = start4 + 498 - 1;
-        subBands.emplace_back(start1, stop1);
-        subBands.emplace_back(start2, stop2);
-        subBands.emplace_back(start3, stop3);
-        subBands.emplace_back(start4, stop4);
-        break;
-    default:
-        NS_FATAL_ERROR("ChannelWidth " << channelWidth << " unsupported");
-        break;
-    }
-
-    // Create punctured bands
-    auto puncturedSlopeWidth =
-        static_cast<uint32_t>((500e3 / carrierSpacing) +
-                              0.5); // size in number of subcarriers of the punctured slope band
-    std::vector<WifiSpectrumBandIndices> puncturedBands;
-    std::size_t subcarriersPerSuband = (20 * 1e6 / carrierSpacing);
-    uint32_t start = (nGuardBands / 2);
-    uint32_t stop = start + subcarriersPerSuband - 1;
-    for (auto puncturedSubchannel : puncturedSubchannels)
-    {
-        if (puncturedSubchannel)
-        {
-            puncturedBands.emplace_back(start, stop);
-        }
-        start = stop + 1;
-        stop = start + subcarriersPerSuband - 1;
-    }
-
-    // Build transmit spectrum mask
-    CreateSpectrumMaskForOfdm(c,
-                              subBands,
-                              maskBand,
-                              txPowerPerBandW,
-                              nGuardBands,
-                              innerSlopeWidth,
-                              minInnerBandDbr,
-                              minOuterBandDbr,
-                              lowestPointDbr,
-                              puncturedBands,
-                              puncturedSlopeWidth);
-    NormalizeSpectrumMask(c, txPowerW);
-    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
-    return c;
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateHeMuOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                              uint16_t channelWidth,
-                                                              double txPowerW,
-                                                              uint16_t guardBandwidth,
-                                                              const WifiSpectrumBandIndices& ru)
-{
-    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << ru.first
-                                    << ru.second);
-    uint32_t carrierSpacing = 78125;
-    Ptr<SpectrumValue> c = Create<SpectrumValue>(
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
-
-    // Build spectrum mask
-    auto vit = c->ValuesBegin();
-    auto bit = c->ConstBandsBegin();
-    double txPowerPerBandW = (txPowerW / (ru.second - ru.first + 1)); // FIXME: null subcarriers
-    uint32_t numBands = c->GetSpectrumModel()->GetNumBands();
-    for (size_t i = 0; i < numBands; i++, vit++, bit++)
-    {
-        if (i < ru.first || i > ru.second) // outside the spectrum mask
-        {
-            *vit = 0.0;
-        }
-        else
-        {
-            *vit = (txPowerPerBandW / (bit->fh - bit->fl));
-        }
-    }
-
-    return c;
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateNoisePowerSpectralDensity(uint32_t centerFrequency,
-                                                         uint16_t channelWidth,
-                                                         uint32_t carrierSpacing,
-                                                         double noiseFigure,
-                                                         uint16_t guardBandwidth)
-{
-    Ptr<SpectrumModel> model =
-        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth);
-    return CreateNoisePowerSpectralDensity(noiseFigure, model);
-}
-
-Ptr<SpectrumValue>
-WifiSpectrumValueHelper::CreateNoisePowerSpectralDensity(double noiseFigureDb,
-                                                         Ptr<SpectrumModel> spectrumModel)
-{
-    NS_LOG_FUNCTION(noiseFigureDb << spectrumModel);
-
-    // see "LTE - From theory to practice"
-    // Section 22.4.4.2 Thermal Noise and Receiver Noise Figure
-    const double kT_dBm_Hz = -174.0; // dBm/Hz
-    double kT_W_Hz = DbmToW(kT_dBm_Hz);
-    double noiseFigureLinear = std::pow(10.0, noiseFigureDb / 10.0);
-    double noisePowerSpectralDensity = kT_W_Hz * noiseFigureLinear;
-
-    Ptr<SpectrumValue> noisePsd = Create<SpectrumValue>(spectrumModel);
-    (*noisePsd) = noisePowerSpectralDensity;
-    NS_LOG_INFO("NoisePowerSpectralDensity has integrated power of " << Integral(*noisePsd));
-    return noisePsd;
-}
-
-void
-WifiSpectrumValueHelper::CreateSpectrumMaskForOfdm(
-    Ptr<SpectrumValue> c,
-    const std::vector<WifiSpectrumBandIndices>& allocatedSubBands,
-    const WifiSpectrumBandIndices& maskBand,
-    double txPowerPerBandW,
-    uint32_t nGuardBands,
-    uint32_t innerSlopeWidth,
-    double minInnerBandDbr,
-    double minOuterBandDbr,
-    double lowestPointDbr,
-    const std::vector<WifiSpectrumBandIndices>& puncturedBands,
-    uint32_t puncturedSlopeWidth)
-{
-    NS_LOG_FUNCTION(c << allocatedSubBands.front().first << allocatedSubBands.back().second
-                      << maskBand.first << maskBand.second << txPowerPerBandW << nGuardBands
-                      << innerSlopeWidth << minInnerBandDbr << minOuterBandDbr << lowestPointDbr
-                      << puncturedSlopeWidth);
-    uint32_t numSubBands = allocatedSubBands.size();
-    uint32_t numBands = c->GetSpectrumModel()->GetNumBands();
-    uint32_t numMaskBands = maskBand.second - maskBand.first + 1;
-    NS_ASSERT(numSubBands && numBands && numMaskBands);
-    NS_LOG_LOGIC("Power per band " << txPowerPerBandW << "W");
-
-    // Different power levels
-    double txPowerRefDbm = (10.0 * std::log10(txPowerPerBandW * 1000.0));
-    double txPowerInnerBandMinDbm = txPowerRefDbm + minInnerBandDbr;
-    double txPowerMiddleBandMinDbm = txPowerRefDbm + minOuterBandDbr;
-    double txPowerOuterBandMinDbm =
-        txPowerRefDbm + lowestPointDbr; // TODO also take into account dBm/MHz constraints
-
-    // Different widths (in number of bands)
-    uint32_t outerSlopeWidth =
-        nGuardBands / 4; // nGuardBands is the total left+right guard band. The left/right outer
-                         // part is half of the left/right guard band.
-    uint32_t middleSlopeWidth = outerSlopeWidth - (innerSlopeWidth / 2);
-    WifiSpectrumBandIndices outerBandLeft(
-        maskBand.first, // to handle cases where allocated channel is
-                        // under WifiPhy configured channel width.
-        maskBand.first + outerSlopeWidth - 1);
-    WifiSpectrumBandIndices middleBandLeft(outerBandLeft.second + 1,
-                                           outerBandLeft.second + middleSlopeWidth);
-    WifiSpectrumBandIndices innerBandLeft(
-        allocatedSubBands.front().first - innerSlopeWidth,
-        allocatedSubBands.front().first -
-            1); // better to place slope based on allocated subcarriers
-    WifiSpectrumBandIndices flatJunctionLeft(
-        middleBandLeft.second + 1,
-        innerBandLeft.first - 1); // in order to handle shift due to guard subcarriers
-    WifiSpectrumBandIndices outerBandRight(
-        maskBand.second - outerSlopeWidth + 1,
-        maskBand.second); // start from outer edge to be able to compute flat junction width
-    WifiSpectrumBandIndices middleBandRight(outerBandRight.first - middleSlopeWidth,
-                                            outerBandRight.first - 1);
-    WifiSpectrumBandIndices innerBandRight(allocatedSubBands.back().second + 1,
-                                           allocatedSubBands.back().second + innerSlopeWidth);
-    WifiSpectrumBandIndices flatJunctionRight(innerBandRight.second + 1, middleBandRight.first - 1);
-    std::ostringstream ss;
-    ss << "outerBandLeft=[" << outerBandLeft.first << ";" << outerBandLeft.second << "] "
-       << "middleBandLeft=[" << middleBandLeft.first << ";" << middleBandLeft.second << "] "
-       << "flatJunctionLeft=[" << flatJunctionLeft.first << ";" << flatJunctionLeft.second << "] "
-       << "innerBandLeft=[" << innerBandLeft.first << ";" << innerBandLeft.second << "] "
-       << "subBands=[" << allocatedSubBands.front().first << ";" << allocatedSubBands.back().second
-       << "] ";
-    if (!puncturedBands.empty())
-    {
-        ss << "puncturedBands=[" << puncturedBands.front().first << ";"
-           << puncturedBands.back().second << "] ";
-    }
-    ss << "innerBandRight=[" << innerBandRight.first << ";" << innerBandRight.second << "] "
-       << "flatJunctionRight=[" << flatJunctionRight.first << ";" << flatJunctionRight.second
-       << "] "
-       << "middleBandRight=[" << middleBandRight.first << ";" << middleBandRight.second << "] "
-       << "outerBandRight=[" << outerBandRight.first << ";" << outerBandRight.second << "] ";
-    NS_LOG_DEBUG(ss.str());
-    NS_ASSERT(numMaskBands ==
-              ((allocatedSubBands.back().second - allocatedSubBands.front().first +
-                1) // equivalent to allocatedBand (includes notches and DC)
-               + 2 * (innerSlopeWidth + middleSlopeWidth + outerSlopeWidth) +
-               (flatJunctionLeft.second - flatJunctionLeft.first + 1) // flat junctions
-               + (flatJunctionRight.second - flatJunctionRight.first + 1)));
-
-    // Different slopes
-    double innerSlope = (-1 * minInnerBandDbr) / innerSlopeWidth;
-    double middleSlope = (-1 * (minOuterBandDbr - minInnerBandDbr)) / middleSlopeWidth;
-    double outerSlope = (txPowerMiddleBandMinDbm - txPowerOuterBandMinDbm) / outerSlopeWidth;
-    double puncturedSlope = (-1 * minInnerBandDbr) / puncturedSlopeWidth;
-
-    // Build spectrum mask
-    auto vit = c->ValuesBegin();
-    auto bit = c->ConstBandsBegin();
-    double txPowerW = 0.0;
-    double previousTxPowerW = 0.0;
-    for (size_t i = 0; i < numBands; i++, vit++, bit++)
-    {
-        if (i < maskBand.first || i > maskBand.second) // outside the spectrum mask
-        {
-            txPowerW = 0.0;
-        }
-        else if (i <= outerBandLeft.second &&
-                 i >= outerBandLeft.first) // better to put greater first (less computation)
-        {
-            txPowerW = DbmToW(txPowerOuterBandMinDbm + ((i - outerBandLeft.first) * outerSlope));
-        }
-        else if (i <= middleBandLeft.second && i >= middleBandLeft.first)
-        {
-            txPowerW = DbmToW(txPowerMiddleBandMinDbm + ((i - middleBandLeft.first) * middleSlope));
-        }
-        else if (i <= flatJunctionLeft.second && i >= flatJunctionLeft.first)
-        {
-            txPowerW = DbmToW(txPowerInnerBandMinDbm);
-        }
-        else if (i <= innerBandLeft.second && i >= innerBandLeft.first)
-        {
-            txPowerW =
-                (!puncturedBands.empty() &&
-                 (puncturedBands.front().first <= allocatedSubBands.front().first))
-                    ? DbmToW(txPowerInnerBandMinDbm)
-                    : // first 20 MHz band is punctured
-                    DbmToW(txPowerInnerBandMinDbm + ((i - innerBandLeft.first) * innerSlope));
-        }
-        else if (i <= allocatedSubBands.back().second &&
-                 i >= allocatedSubBands.front().first) // roughly in allocated band
-        {
-            bool insideSubBand = false;
-            for (uint32_t j = 0; !insideSubBand && j < numSubBands;
-                 j++) // continue until inside a sub-band
-            {
-                insideSubBand =
-                    (i <= allocatedSubBands[j].second) && (i >= allocatedSubBands[j].first);
-            }
-            if (insideSubBand)
-            {
-                bool insidePuncturedSubBand = false;
-                uint32_t j = 0;
-                for (; !insidePuncturedSubBand && j < puncturedBands.size();
-                     j++) // continue until inside a punctured sub-band
-                {
-                    insidePuncturedSubBand =
-                        (i <= puncturedBands[j].second) && (i >= puncturedBands[j].first);
-                }
-                if (insidePuncturedSubBand)
-                {
-                    uint32_t startPuncturedSlope =
-                        (puncturedBands[puncturedBands.size() - 1].second -
-                         puncturedSlopeWidth); // only consecutive subchannels can be punctured
-                    if (i >= startPuncturedSlope)
-                    {
-                        txPowerW = DbmToW(txPowerInnerBandMinDbm +
-                                          ((i - startPuncturedSlope) * puncturedSlope));
-                    }
-                    else
-                    {
-                        txPowerW = std::max(DbmToW(txPowerInnerBandMinDbm),
-                                            DbmToW(txPowerRefDbm - ((i - puncturedBands[0].first) *
-                                                                    puncturedSlope)));
-                    }
-                }
-                else
-                {
-                    txPowerW = txPowerPerBandW;
-                }
-            }
-            else
-            {
-                txPowerW = DbmToW(txPowerInnerBandMinDbm);
-            }
-        }
-        else if (i <= innerBandRight.second && i >= innerBandRight.first)
-        {
-            // take min to handle the case where last 20 MHz band is punctured
-            txPowerW = std::min(
-                previousTxPowerW,
-                DbmToW(txPowerRefDbm - ((i - innerBandRight.first + 1) *
-                                        innerSlope))); // +1 so as to be symmetric with left slope
-        }
-        else if (i <= flatJunctionRight.second && i >= flatJunctionRight.first)
-        {
-            txPowerW = DbmToW(txPowerInnerBandMinDbm);
-        }
-        else if (i <= middleBandRight.second && i >= middleBandRight.first)
-        {
-            txPowerW = DbmToW(txPowerInnerBandMinDbm -
-                              ((i - middleBandRight.first + 1) *
-                               middleSlope)); // +1 so as to be symmetric with left slope
-        }
-        else if (i <= outerBandRight.second && i >= outerBandRight.first)
-        {
-            txPowerW = DbmToW(txPowerMiddleBandMinDbm -
-                              ((i - outerBandRight.first + 1) *
-                               outerSlope)); // +1 so as to be symmetric with left slope
-        }
-        else
-        {
-            NS_FATAL_ERROR("Should have handled all cases");
-        }
-        double txPowerDbr = 10 * std::log10(txPowerW / txPowerPerBandW);
-        NS_LOG_LOGIC(uint32_t(i) << " -> " << txPowerDbr);
-        *vit = txPowerW / (bit->fh - bit->fl);
-        previousTxPowerW = txPowerW;
-    }
-    NS_LOG_INFO("Added signal power to subbands " << allocatedSubBands.front().first << "-"
-                                                  << allocatedSubBands.back().second);
-}
-
-void
-WifiSpectrumValueHelper::NormalizeSpectrumMask(Ptr<SpectrumValue> c, double txPowerW)
-{
-    NS_LOG_FUNCTION(c << txPowerW);
-    // Normalize power so that total signal power equals transmit power
-    double currentTxPowerW = Integral(*c);
-    double normalizationRatio = currentTxPowerW / txPowerW;
-    NS_LOG_LOGIC("Current power: " << currentTxPowerW << "W vs expected power: " << txPowerW << "W"
-                                   << " -> ratio (C/E) = " << normalizationRatio);
-    auto vit = c->ValuesBegin();
-    for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++)
-    {
-        *vit = (*vit) / normalizationRatio;
-    }
-}
-
-double
-WifiSpectrumValueHelper::DbmToW(double dBm)
-{
-    return std::pow(10.0, 0.1 * (dBm - 30.0));
-}
-
-double
-WifiSpectrumValueHelper::GetBandPowerW(Ptr<SpectrumValue> psd, const WifiSpectrumBandIndices& band)
-{
-    double powerWattPerHertz = 0.0;
-    auto valueIt = psd->ConstValuesBegin() + band.first;
-    auto end = psd->ConstValuesBegin() + band.second;
-    auto bandIt = psd->ConstBandsBegin() + band.first;
-    while (valueIt <= end)
-    {
-        powerWattPerHertz += *valueIt;
-        ++valueIt;
-    }
-    return powerWattPerHertz * (bandIt->fh - bandIt->fl);
-}
-
-bool
-operator<(const FrequencyRange& left, const FrequencyRange& right)
-{
-    return left.minFrequency < right.minFrequency;
-}
-
-bool
-operator==(const FrequencyRange& left, const FrequencyRange& right)
-{
-    return (left.minFrequency == right.minFrequency) && (left.maxFrequency == right.maxFrequency);
-}
-
-bool
-operator!=(const FrequencyRange& left, const FrequencyRange& right)
-{
-    return !(left == right);
-}
-
-std::ostream&
-operator<<(std::ostream& os, const FrequencyRange& freqRange)
-{
-    os << "[" << freqRange.minFrequency << " MHz - " << freqRange.maxFrequency << " MHz]";
-    return os;
-}
-
-} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/model/wifi-spectrum-value-helper.h ns-3.42/src/spectrum/model/wifi-spectrum-value-helper.h
--- ns-3.41/src/spectrum/model/wifi-spectrum-value-helper.h	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/model/wifi-spectrum-value-helper.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,394 +0,0 @@
-/*
- * Copyright (c) 2009 CTTC
- * Copyright (c) 2017 Orange Labs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Authors: Nicola Baldo <nbaldo@cttc.es>
- *          Rediet <getachew.redieteab@orange.com>
- */
-
-#ifndef WIFI_SPECTRUM_VALUE_HELPER_H
-#define WIFI_SPECTRUM_VALUE_HELPER_H
-
-#include "spectrum-value.h"
-
-namespace ns3
-{
-
-/**
- * typedef for a pair of start and stop sub-band indices
- */
-using WifiSpectrumBandIndices = std::pair<uint32_t, uint32_t>;
-
-/**
- * \ingroup spectrum
- *
- *  This class defines all functions to create a spectrum model for
- *  Wi-Fi based on a a spectral model aligned with an OFDM subcarrier
- *  spacing of 312.5 KHz (model also reused for DSSS modulations)
- */
-class WifiSpectrumValueHelper
-{
-  public:
-    /**
-     * Destructor
-     */
-    virtual ~WifiSpectrumValueHelper() = default;
-
-    /**
-     * Return a SpectrumModel instance corresponding to the center frequency
-     * and channel width.  The spectrum model spans the channel width
-     * +/- the guard bands (i.e. the model will span (channelWidth +
-     * 2 * guardBandwidth) MHz of bandwidth).
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param carrierSpacing carrier spacing (Hz)
-     * \param guardBandwidth width of the guard band (MHz)
-     *
-     * \return the static SpectrumModel instance corresponding to the
-     * given carrier frequency and channel width configuration.
-     */
-    static Ptr<SpectrumModel> GetSpectrumModel(uint32_t centerFrequency,
-                                               uint16_t channelWidth,
-                                               uint32_t carrierSpacing,
-                                               uint16_t guardBandwidth);
-
-    /**
-     * Create a transmit power spectral density corresponding to DSSS
-     *
-     * The center frequency typically corresponds to 802.11b channel
-     * center frequencies but is not restricted to those frequencies.
-     *
-     * \note There is no channel width parameter; this method assumes 22 MHz
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param txPowerW  transmit power (W) to allocate
-     * \param guardBandwidth width of the guard band (MHz)
-     * \returns a pointer to a newly allocated SpectrumValue representing the DSSS Transmit Power
-     * Spectral Density in W/Hz
-     */
-    static Ptr<SpectrumValue> CreateDsssTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                               double txPowerW,
-                                                               uint16_t guardBandwidth);
-
-    /**
-     * Create a transmit power spectral density corresponding to OFDM
-     * (802.11a/g).  Channel width may vary between 20, 10, and 5 MHz.
-     * Guard bandwidth also typically varies with channel width.
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param txPowerW  transmit power (W) to allocate
-     * \param guardBandwidth width of the guard band (MHz)
-     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
-     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
-     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
-     * (in dBr)
-     * \return a pointer to a newly allocated SpectrumValue representing the OFDM Transmit Power
-     * Spectral Density in W/Hz for each Band
-     */
-    static Ptr<SpectrumValue> CreateOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                               uint16_t channelWidth,
-                                                               double txPowerW,
-                                                               uint16_t guardBandwidth,
-                                                               double minInnerBandDbr = -20,
-                                                               double minOuterbandDbr = -28,
-                                                               double lowestPointDbr = -40);
-
-    /**
-     * Create a transmit power spectral density corresponding to OFDM duplicated over multiple 20
-     * MHz subchannels. Channel width may vary between 20, 40, 80, and 160 MHz.
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param txPowerW  transmit power (W) to allocate
-     * \param guardBandwidth width of the guard band (MHz)
-     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
-     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
-     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
-     * (in dBr)
-     * \param puncturedSubchannels bitmap indicating whether a 20 MHz subchannel is punctured or not
-     * \return a pointer to a newly allocated SpectrumValue representing the duplicated 20 MHz OFDM
-     * Transmit Power Spectral Density in W/Hz for each Band
-     */
-    static Ptr<SpectrumValue> CreateDuplicated20MhzTxPowerSpectralDensity(
-        uint32_t centerFrequency,
-        uint16_t channelWidth,
-        double txPowerW,
-        uint16_t guardBandwidth,
-        double minInnerBandDbr = -20,
-        double minOuterbandDbr = -28,
-        double lowestPointDbr = -40,
-        const std::vector<bool>& puncturedSubchannels = std::vector<bool>{});
-
-    /**
-     * Create a transmit power spectral density corresponding to OFDM
-     * High Throughput (HT) (802.11n/ac).  Channel width may vary between
-     * 20, 40, 80, and 160 MHz.
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param txPowerW  transmit power (W) to allocate
-     * \param guardBandwidth width of the guard band (MHz)
-     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
-     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
-     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
-     * (in dBr)
-     * \return a pointer to a newly allocated SpectrumValue representing the HT OFDM Transmit Power
-     * Spectral Density in W/Hz for each Band
-     */
-    static Ptr<SpectrumValue> CreateHtOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
-                                                                 uint16_t channelWidth,
-                                                                 double txPowerW,
-                                                                 uint16_t guardBandwidth,
-                                                                 double minInnerBandDbr = -20,
-                                                                 double minOuterbandDbr = -28,
-                                                                 double lowestPointDbr = -40);
-
-    /**
-     * Create a transmit power spectral density corresponding to OFDM
-     * High Efficiency (HE) (802.11ax).  Channel width may vary between
-     * 20, 40, 80, and 160 MHz.
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param txPowerW  transmit power (W) to allocate
-     * \param guardBandwidth width of the guard band (MHz)
-     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
-     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
-     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
-     * (in dBr)
-     * \param puncturedSubchannels bitmap indicating whether a 20 MHz subchannel is punctured or not
-     * \return a pointer to a newly allocated SpectrumValue representing the HE OFDM Transmit Power
-     * Spectral Density in W/Hz for each Band
-     */
-    static Ptr<SpectrumValue> CreateHeOfdmTxPowerSpectralDensity(
-        uint32_t centerFrequency,
-        uint16_t channelWidth,
-        double txPowerW,
-        uint16_t guardBandwidth,
-        double minInnerBandDbr = -20,
-        double minOuterbandDbr = -28,
-        double lowestPointDbr = -40,
-        const std::vector<bool>& puncturedSubchannels = std::vector<bool>{});
-
-    /**
-     * Create a transmit power spectral density corresponding to the OFDMA part
-     * of HE TB PPDUs for a given RU.
-     * An ideal (i.e. rectangular) spectral mask is considered for the time being.
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param txPowerW  transmit power (W) to allocate
-     * \param guardBandwidth width of the guard band (MHz)
-     * \param ru the RU band used by the STA
-     * \return a pointer to a newly allocated SpectrumValue representing the HE OFDM Transmit Power
-     * Spectral Density on the RU used by the STA in W/Hz for each Band
-     */
-    static Ptr<SpectrumValue> CreateHeMuOfdmTxPowerSpectralDensity(
-        uint32_t centerFrequency,
-        uint16_t channelWidth,
-        double txPowerW,
-        uint16_t guardBandwidth,
-        const WifiSpectrumBandIndices& ru);
-
-    /**
-     * Create a power spectral density corresponding to the noise
-     *
-     * \param centerFrequency center frequency (MHz)
-     * \param channelWidth channel width (MHz)
-     * \param carrierSpacing carrier spacing (Hz)
-     * \param noiseFigure the noise figure in dB w.r.t. a reference temperature of 290K
-     * \param guardBandwidth width of the guard band (MHz)
-     * \return a pointer to a newly allocated SpectrumValue representing the noise Power Spectral
-     * Density in W/Hz for each Band
-     */
-    static Ptr<SpectrumValue> CreateNoisePowerSpectralDensity(uint32_t centerFrequency,
-                                                              uint16_t channelWidth,
-                                                              uint32_t carrierSpacing,
-                                                              double noiseFigure,
-                                                              uint16_t guardBandwidth);
-
-    /**
-     * Create a thermal noise power spectral density
-     *
-     * \param noiseFigure the noise figure
-     * \param spectrumModel the spectrum model
-     * \return a pointer to a newly allocated SpectrumValue representing the noise Power Spectral
-     * Density in W/Hz corresponding to thermal noise, for each Band
-     */
-    static Ptr<SpectrumValue> CreateNoisePowerSpectralDensity(double noiseFigure,
-                                                              Ptr<SpectrumModel> spectrumModel);
-
-    /**
-     * Create a transmit power spectral density corresponding to OFDM
-     * transmit spectrum mask requirements for 11a/11g/11n/11ac/11ax
-     * Channel width may vary between 5, 10, 20, 40, 80, and 160 MHz.
-     * The default (standard) values are illustrated below.
-     *
-     *   [ guard band  ][    channel width     ][  guard band ]
-     *                   __________   __________                  _ 0 dBr
-     *                  /          | |          \
-     *                 /           |_|           \                _ -20 dBr
-     *             . '                             ' .
-     *         . '                                     ' .        _ -28 dBr
-     *       .'                                           '.
-     *     .'                                               '.
-     *   .'                                                   '.  _ lowest point
-     *
-     *   |-----|                                         |-----|  outerBand left/right
-     *         |------|                           |-- ---|        middle band left/right
-     *                |-|                       |-|               inner band left/right
-     *                  |-----------------------|                 allocated sub-bands
-     *   |-----------------------------------------------------|  mask band
-     *
-     * Please take note that, since guard tones are within the allocated band
-     * while not being ideally allocated any power, the inner band had to be
-     * shifted inwards and a flat junction band (at -20 dBr) had to be added
-     * between the inner and the middle bands.
-     *
-     * \param c spectrumValue to allocate according to transmit power spectral density mask (in W/Hz
-     * for each band)
-     * \param allocatedSubBands vector of start and stop subcarrier indexes of the allocated sub
-     * bands
-     * \param maskBand start and stop subcarrier indexes of transmit mask (in case signal doesn't
-     * cover whole SpectrumModel)
-     * \param txPowerPerBandW power allocated to each subcarrier in the allocated sub bands
-     * \param nGuardBands size (in number of subcarriers) of the guard band (left and right)
-     * \param innerSlopeWidth size (in number of subcarriers) of the inner band (i.e. slope going
-     * from 0 dBr to -20 dBr in the figure above)
-     * \param minInnerBandDbr the minimum relative power in the inner band (i.e., -20 dBr in the
-     * figure above)
-     * \param minOuterbandDbr the minimum relative power in the outer band (i.e., -28 dBr in the
-     * figure above)
-     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
-     * (in dBr)
-     * \param puncturedSubBands vector of start and stop subcarrier indexes of the punctured sub
-     * bands
-     * \param puncturedSlopeWidth size (in number of subcarriers) of the punctured band slope
-     */
-    static void CreateSpectrumMaskForOfdm(
-        Ptr<SpectrumValue> c,
-        const std::vector<WifiSpectrumBandIndices>& allocatedSubBands,
-        const WifiSpectrumBandIndices& maskBand,
-        double txPowerPerBandW,
-        uint32_t nGuardBands,
-        uint32_t innerSlopeWidth,
-        double minInnerBandDbr,
-        double minOuterbandDbr,
-        double lowestPointDbr,
-        const std::vector<WifiSpectrumBandIndices>& puncturedSubBands =
-            std::vector<WifiSpectrumBandIndices>{},
-        uint32_t puncturedSlopeWidth = 0);
-
-    /**
-     * Normalize the transmit spectrum mask generated by CreateSpectrumMaskForOfdm
-     * so that the total transmitted power corresponds to the input value.
-     *
-     * \param c spectrumValue to normalize (in W/Hz for each band)
-     * \param txPowerW total transmit power (W) to allocate
-     */
-    static void NormalizeSpectrumMask(Ptr<SpectrumValue> c, double txPowerW);
-
-    /**
-     * Convert from dBm to Watts.
-     * Taken from wifi-utils since the original method couldn't be called from here
-     * due to resulting circular dependencies of spectrum and wifi modules.
-     *
-     * \param dbm the power in dBm
-     *
-     * \return the equivalent Watts for the given dBm
-     */
-    static double DbmToW(double dbm);
-
-    /**
-     * Calculate the power of the specified band composed of uniformly-sized sub-bands.
-     *
-     * \param psd received Power Spectral Density in W/Hz
-     * \param band a pair of start and stop indexes that defines the band
-     *
-     * \return band power in W
-     */
-    static double GetBandPowerW(Ptr<SpectrumValue> psd, const WifiSpectrumBandIndices& band);
-};
-
-/**
- * \ingroup spectrum
- * Struct defining a frequency range between minFrequency (MHz) and maxFrequency (MHz).
- */
-struct FrequencyRange
-{
-    uint16_t minFrequency{0}; ///< the minimum frequency in MHz
-    uint16_t maxFrequency{0}; ///< the maximum frequency in MHz
-};
-
-/**
- * Compare two FrequencyRange values
- *
- * \param lhs the FrequencyRange value on the left of operator
- * \param rhs the FrequencyRange value on the right of operator
- *
- * \return true if minFrequency of left is less than minFrequency of right, false otherwise
- */
-bool operator<(const FrequencyRange& lhs, const FrequencyRange& rhs);
-
-/**
- * Compare two FrequencyRange values
- *
- * \param lhs the FrequencyRange value on the left of operator
- * \param rhs the FrequencyRange value on the right of operator
- *
- * \return true if both minFrequency and maxFrequency of left are equal to minFrequency and
- * maxFrequency of right respectively, false otherwise
- */
-bool operator==(const FrequencyRange& lhs, const FrequencyRange& rhs);
-
-/**
- * Compare two FrequencyRange values
- *
- * \param lhs the FrequencyRange value on the left of operator
- * \param rhs the FrequencyRange value on the right of operator
- *
- * \return true if either minFrequency or maxFrequency of left different from minFrequency or
- * maxFrequency of right respectively, false otherwise
- */
-bool operator!=(const FrequencyRange& lhs, const FrequencyRange& rhs);
-
-/**
- * Serialize FrequencyRange values to ostream (human-readable).
- *
- * \param os the output stream
- * \param freqRange the FrequencyRange
- *
- * \return std::ostream
- */
-std::ostream& operator<<(std::ostream& os, const FrequencyRange& freqRange);
-
-/// Identifier for the frequency range covering the whole wifi spectrum
-constexpr FrequencyRange WHOLE_WIFI_SPECTRUM = {2401, 7125};
-
-/// Identifier for the frequency range covering the wifi spectrum in the 2.4 GHz band
-constexpr FrequencyRange WIFI_SPECTRUM_2_4_GHZ = {2401, 2483};
-
-/// Identifier for the frequency range covering the wifi spectrum in the 5 GHz band
-constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ = {5170, 5915};
-
-/// Identifier for the frequency range covering the wifi spectrum in the 6 GHz band
-constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ = {5945, 7125};
-
-} // namespace ns3
-
-#endif /*  WIFI_SPECTRUM_VALUE_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/spectrum-ideal-phy-test.cc ns-3.42/src/spectrum/test/spectrum-ideal-phy-test.cc
--- ns-3.41/src/spectrum/test/spectrum-ideal-phy-test.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/spectrum-ideal-phy-test.cc	2024-05-29 15:29:47.172073600 -0700
@@ -240,7 +240,7 @@
 };
 
 SpectrumIdealPhyTestSuite::SpectrumIdealPhyTestSuite()
-    : TestSuite("spectrum-ideal-phy", SYSTEM)
+    : TestSuite("spectrum-ideal-phy", Type::SYSTEM)
 {
     NS_LOG_INFO("creating SpectrumIdealPhyTestSuite");
 
@@ -251,32 +251,32 @@
                                                  static_cast<uint64_t>(achievableRate * 0.1),
                                                  true,
                                                  "ns3::SingleModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 0.5),
                                                  true,
                                                  "ns3::SingleModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 0.95),
                                                  true,
                                                  "ns3::SingleModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 1.05),
                                                  false,
                                                  "ns3::SingleModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 2),
                                                  false,
                                                  "ns3::SingleModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 4),
                                                  false,
                                                  "ns3::SingleModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
     for (double snr = 0.01; snr <= 10; snr *= 10)
     {
@@ -285,32 +285,32 @@
                                                  static_cast<uint64_t>(achievableRate * 0.1),
                                                  true,
                                                  "ns3::MultiModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 0.5),
                                                  true,
                                                  "ns3::MultiModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 0.95),
                                                  true,
                                                  "ns3::MultiModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 1.05),
                                                  false,
                                                  "ns3::MultiModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 2),
                                                  false,
                                                  "ns3::MultiModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new SpectrumIdealPhyTestCase(snr,
                                                  static_cast<uint64_t>(achievableRate * 4),
                                                  false,
                                                  "ns3::MultiModelSpectrumChannel"),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/spectrum-interference-test.cc ns-3.42/src/spectrum/test/spectrum-interference-test.cc
--- ns-3.41/src/spectrum/test/spectrum-interference-test.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/spectrum-interference-test.cc	2024-05-29 15:29:47.172073600 -0700
@@ -152,7 +152,7 @@
 };
 
 SpectrumInterferenceTestSuite::SpectrumInterferenceTestSuite()
-    : TestSuite("spectrum-interference", UNIT)
+    : TestSuite("spectrum-interference", Type::UNIT)
 {
     NS_LOG_INFO("creating SpectrumInterferenceTestSuite");
 
@@ -184,32 +184,32 @@
     (*s1)[1] = 7.204059965732e-16;
     b = 10067205.5632012;
     AddTestCase(new SpectrumInterferenceTestCase(s1, 0, true, "sdBm  = [-46 -48]  tx bytes: 1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s1,
                                                  static_cast<uint32_t>(b * 0.5 + 0.5),
                                                  true,
                                                  "sdBm  = [-46 -48]  tx bytes: b*0.5"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s1,
                                                  static_cast<uint32_t>(b * (1 - e) + 0.5),
                                                  true,
                                                  "sdBm  = [-46 -48]  tx bytes: b*(1-e)"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s1,
                                                  static_cast<uint32_t>(b * (1 + e) + 0.5),
                                                  false,
                                                  "sdBm  = [-46 -48]  tx bytes: b*(1+e)"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s1,
                                                  static_cast<uint32_t>(b * 1.5 + 0.5),
                                                  false,
                                                  "sdBm  = [-46 -48]  tx bytes: b*1.5"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s1,
                                                  0xffffffff,
                                                  false,
                                                  "sdBm  = [-46 -48]  tx bytes: 2^32-1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Power Spectral Density of the signal of interest  =  [-63 -61] dBm;
     Ptr<SpectrumValue> s2 = Create<SpectrumValue>(m);
@@ -217,32 +217,32 @@
     (*s2)[1] = 3.610582885110e-17;
     b = 882401.591840728;
     AddTestCase(new SpectrumInterferenceTestCase(s2, 1, true, "sdBm  = [-63 -61]  tx bytes: 1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s2,
                                                  static_cast<uint32_t>(b * 0.5 + 0.5),
                                                  true,
                                                  "sdBm  = [-63 -61]  tx bytes: b*0.5"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s2,
                                                  static_cast<uint32_t>(b * (1 - e) + 0.5),
                                                  true,
                                                  "sdBm  = [-63 -61]  tx bytes: b*(1-e)"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s2,
                                                  static_cast<uint32_t>(b * (1 + e) + 0.5),
                                                  false,
                                                  "sdBm  = [-63 -61]  tx bytes: b*(1+e)"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s2,
                                                  static_cast<uint32_t>(b * 1.5 + 0.5),
                                                  false,
                                                  "sdBm  = [-63 -61]  tx bytes: b*1.5"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumInterferenceTestCase(s2,
                                                  0xffffffff,
                                                  false,
                                                  "sdBm  = [-63 -61]  tx bytes: 2^32-1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/spectrum-value-test.cc ns-3.42/src/spectrum/test/spectrum-value-test.cc
--- ns-3.41/src/spectrum/test/spectrum-value-test.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/spectrum-value-test.cc	2024-05-29 15:29:47.172073600 -0700
@@ -105,7 +105,7 @@
 };
 
 SpectrumValueTestSuite::SpectrumValueTestSuite()
-    : TestSuite("spectrum-value", UNIT)
+    : TestSuite("spectrum-value", Type::UNIT)
 {
     // NS_LOG_INFO("creating SpectrumValueTestSuite");
 
@@ -203,10 +203,10 @@
     tv5 = v1 * v2;
     tv6 = v1 / v2;
 
-    AddTestCase(new SpectrumValueTestCase(tv3, v3, "tv3 = v1 + v2"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv4, v4, "tv4 = v1 - v2"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv5, v5, "tv5 = v1 * v2"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv6, v6, "tv6 = v1 div v2"), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv3, v3, "tv3 = v1 + v2"), TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv4, v4, "tv4 = v1 - v2"), TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv5, v5, "tv5 = v1 * v2"), TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv6, v6, "tv6 = v1 div v2"), TestCase::Duration::QUICK);
 
     // std::cerr << v6 << std::endl;
     // std::cerr << tv6 << std::endl;
@@ -221,10 +221,10 @@
     tv5 *= v2;
     tv6 /= v2;
 
-    AddTestCase(new SpectrumValueTestCase(tv3, v3, "tv3 += v2"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv4, v4, "tv4 -= v2"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv5, v5, "tv5 *= v2"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv6, v6, "tv6 div= v2"), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv3, v3, "tv3 += v2"), TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv4, v4, "tv4 -= v2"), TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv5, v5, "tv5 *= v2"), TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv6, v6, "tv6 div= v2"), TestCase::Duration::QUICK);
 
     SpectrumValue tv7a(f);
     SpectrumValue tv8a(f);
@@ -234,11 +234,14 @@
     tv8a = v1 - doubleValue;
     tv9a = v1 * doubleValue;
     tv10a = v1 / doubleValue;
-    AddTestCase(new SpectrumValueTestCase(tv7a, v7, "tv7a = v1 + doubleValue"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv8a, v8, "tv8a = v1 - doubleValue"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv9a, v9, "tv9a = v1 * doubleValue"), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv7a, v7, "tv7a = v1 + doubleValue"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv8a, v8, "tv8a = v1 - doubleValue"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv9a, v9, "tv9a = v1 * doubleValue"),
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumValueTestCase(tv10a, v10, "tv10a = v1 div doubleValue"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     SpectrumValue tv7b(f);
     SpectrumValue tv8b(f);
@@ -248,11 +251,14 @@
     tv8b = doubleValue - v1;
     tv9b = doubleValue * v1;
     tv10b = doubleValue / v1;
-    AddTestCase(new SpectrumValueTestCase(tv7b, v7, "tv7b =  doubleValue + v1"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv8b, v8, "tv8b =  doubleValue - v1"), TestCase::QUICK);
-    AddTestCase(new SpectrumValueTestCase(tv9b, v9, "tv9b =  doubleValue * v1"), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv7b, v7, "tv7b =  doubleValue + v1"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv8b, v8, "tv8b =  doubleValue - v1"),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv9b, v9, "tv9b =  doubleValue * v1"),
+                TestCase::Duration::QUICK);
     AddTestCase(new SpectrumValueTestCase(tv10b, v10, "tv10b = doubleValue div v1"),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     SpectrumValue v1ls3(f);
     SpectrumValue v1rs3(f);
@@ -262,12 +268,14 @@
     v1ls3[0] = v1[3];
     v1ls3[1] = v1[4];
     tv1ls3 = v1 << 3;
-    AddTestCase(new SpectrumValueTestCase(tv1ls3, v1ls3, "tv1ls3 = v1 << 3"), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv1ls3, v1ls3, "tv1ls3 = v1 << 3"),
+                TestCase::Duration::QUICK);
 
     v1rs3[3] = v1[0];
     v1rs3[4] = v1[1];
     tv1rs3 = v1 >> 3;
-    AddTestCase(new SpectrumValueTestCase(tv1rs3, v1rs3, "tv1rs3 = v1 >> 3"), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(tv1rs3, v1rs3, "tv1rs3 = v1 >> 3"),
+                TestCase::Duration::QUICK);
 }
 
 /**
@@ -282,7 +290,7 @@
 };
 
 SpectrumConverterTestSuite::SpectrumConverterTestSuite()
-    : TestSuite("spectrum-converter", UNIT)
+    : TestSuite("spectrum-converter", Type::UNIT)
 {
     double f;
 
@@ -314,7 +322,7 @@
     //   NS_LOG_LOGIC(t12);
     //   NS_LOG_LOGIC(*res);
 
-    AddTestCase(new SpectrumValueTestCase(t12, *res, ""), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(t12, *res, ""), TestCase::Duration::QUICK);
     // TEST_ASSERT(MoreOrLessEqual(t12, *res));
 
     Ptr<SpectrumValue> v2a = Create<SpectrumValue>(sof2);
@@ -326,7 +334,7 @@
     //   NS_LOG_LOGIC(*v2a);
     //   NS_LOG_LOGIC(t21a);
     //   NS_LOG_LOGIC(*res);
-    AddTestCase(new SpectrumValueTestCase(t21a, *res, ""), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(t21a, *res, ""), TestCase::Duration::QUICK);
     // TEST_ASSERT(MoreOrLessEqual(t21a, *res));
 
     Ptr<SpectrumValue> v2b = Create<SpectrumValue>(sof2);
@@ -345,7 +353,7 @@
     //   NS_LOG_LOGIC(*v2b);
     //   NS_LOG_LOGIC(t21b);
     //   NS_LOG_LOGIC(*res);
-    AddTestCase(new SpectrumValueTestCase(t21b, *res, ""), TestCase::QUICK);
+    AddTestCase(new SpectrumValueTestCase(t21b, *res, ""), TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/spectrum-waveform-generator-test.cc ns-3.42/src/spectrum/test/spectrum-waveform-generator-test.cc
--- ns-3.41/src/spectrum/test/spectrum-waveform-generator-test.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/spectrum-waveform-generator-test.cc	2024-05-29 15:29:47.172073600 -0700
@@ -127,14 +127,14 @@
 };
 
 WaveformGeneratorTestSuite::WaveformGeneratorTestSuite()
-    : TestSuite("waveform-generator", SYSTEM)
+    : TestSuite("waveform-generator", Type::SYSTEM)
 {
     NS_LOG_INFO("creating WaveformGeneratorTestSuite");
 
     // Stop while wave is active
-    AddTestCase(new WaveformGeneratorTestCase(1.0, 0.5, 1.2), TestCase::QUICK);
+    AddTestCase(new WaveformGeneratorTestCase(1.0, 0.5, 1.2), TestCase::Duration::QUICK);
     // Stop after wave
-    AddTestCase(new WaveformGeneratorTestCase(1.0, 0.5, 1.7), TestCase::QUICK);
+    AddTestCase(new WaveformGeneratorTestCase(1.0, 0.5, 1.7), TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/three-gpp-channel-test-suite.cc ns-3.42/src/spectrum/test/three-gpp-channel-test-suite.cc
--- ns-3.41/src/spectrum/test/three-gpp-channel-test-suite.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/three-gpp-channel-test-suite.cc	2024-05-29 15:29:47.172073600 -0700
@@ -498,6 +498,234 @@
 
 /**
  * \ingroup spectrum-tests
+ *
+ * Test case for the ThreeGppChannelModel class.
+ * It checks if the channel realizations are correctly
+ * updated after a change in the number of antenna elements.
+ */
+class ThreeGppAntennaSetupChangedTest : public TestCase
+{
+  public:
+    /**
+     * Constructor
+     */
+    ThreeGppAntennaSetupChangedTest();
+
+    /**
+     * Destructor
+     */
+    ~ThreeGppAntennaSetupChangedTest() override;
+
+  private:
+    /**
+     * Build the test scenario
+     */
+    void DoRun() override;
+
+    /**
+     * This method is used to schedule the channel matrix computation at different
+     * time instants and to check if it correctly updated
+     * \param channelModel the ThreeGppChannelModel object used to generate the channel matrix
+     * \param txMob the mobility model of the first node
+     * \param rxMob the mobility model of the second node
+     * \param txAntenna the antenna object associated to the first node
+     * \param rxAntenna the antenna object associated to the second node
+     * \param update whether if the channel matrix should be updated or not
+     */
+    void DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
+                      Ptr<MobilityModel> txMob,
+                      Ptr<MobilityModel> rxMob,
+                      Ptr<PhasedArrayModel> txAntenna,
+                      Ptr<PhasedArrayModel> rxAntenna,
+                      bool update);
+
+    Ptr<const ThreeGppChannelModel::ChannelMatrix>
+        m_currentChannel;            //!< used by DoGetChannel to store the current channel matrix
+    uint32_t m_txAntennaElements{4}; //!< number of rows and columns of tx antenna array
+    uint32_t m_rxAntennaElements{4}; //!< number of rows and columns of rx antenna array
+    uint32_t m_txPorts{1}; //!< number of horizontal and vertical ports of tx antenna array
+    uint32_t m_rxPorts{1}; //!< number of horizontal and vertical ports of rx antenna array
+};
+
+ThreeGppAntennaSetupChangedTest::ThreeGppAntennaSetupChangedTest()
+    : TestCase("Check if the channel realizations are correctly updated after antenna port changes "
+               "during the simulation")
+{
+}
+
+ThreeGppAntennaSetupChangedTest::~ThreeGppAntennaSetupChangedTest()
+{
+}
+
+void
+ThreeGppAntennaSetupChangedTest::DoGetChannel(Ptr<ThreeGppChannelModel> channelModel,
+                                              Ptr<MobilityModel> txMob,
+                                              Ptr<MobilityModel> rxMob,
+                                              Ptr<PhasedArrayModel> txAntenna,
+                                              Ptr<PhasedArrayModel> rxAntenna,
+                                              bool update)
+{
+    // retrieve the channel matrix
+    Ptr<const ThreeGppChannelModel::ChannelMatrix> channelMatrix =
+        channelModel->GetChannel(txMob, rxMob, txAntenna, rxAntenna);
+
+    if (m_currentChannel)
+    {
+        // compare the old and the new channel matrices
+        NS_TEST_ASSERT_MSG_EQ((m_currentChannel->m_channel != channelMatrix->m_channel),
+                              update,
+                              Simulator::Now().GetMilliSeconds()
+                                  << " The channel matrix is not correctly updated");
+    }
+    m_currentChannel = channelMatrix;
+}
+
+void
+ThreeGppAntennaSetupChangedTest::DoRun()
+{
+    // Build the scenario for the test
+    uint32_t updatePeriodMs = 100; // update period in ms
+
+    // create the channel condition model
+    Ptr<ChannelConditionModel> channelConditionModel =
+        CreateObject<AlwaysLosChannelConditionModel>();
+
+    // create the ThreeGppChannelModel object used to generate the channel matrix
+    Ptr<ThreeGppChannelModel> channelModel = CreateObject<ThreeGppChannelModel>();
+    channelModel->SetAttribute("Frequency", DoubleValue(60.0e9));
+    channelModel->SetAttribute("Scenario", StringValue("UMa"));
+    channelModel->SetAttribute("ChannelConditionModel", PointerValue(channelConditionModel));
+    channelModel->SetAttribute("UpdatePeriod", TimeValue(MilliSeconds(updatePeriodMs)));
+
+    // create the tx and rx nodes
+    NodeContainer nodes;
+    nodes.Create(2);
+
+    // create the tx and rx devices
+    Ptr<SimpleNetDevice> txDev = CreateObject<SimpleNetDevice>();
+    Ptr<SimpleNetDevice> rxDev = CreateObject<SimpleNetDevice>();
+
+    // associate the nodes and the devices
+    nodes.Get(0)->AddDevice(txDev);
+    txDev->SetNode(nodes.Get(0));
+    nodes.Get(1)->AddDevice(rxDev);
+    rxDev->SetNode(nodes.Get(1));
+
+    // create the tx and rx mobility models and set their positions
+    Ptr<MobilityModel> txMob = CreateObject<ConstantPositionMobilityModel>();
+    txMob->SetPosition(Vector(0.0, 0.0, 10.0));
+    Ptr<MobilityModel> rxMob = CreateObject<ConstantPositionMobilityModel>();
+    rxMob->SetPosition(Vector(100.0, 0.0, 1.6));
+
+    // associate the nodes and the mobility models
+    nodes.Get(0)->AggregateObject(txMob);
+    nodes.Get(1)->AggregateObject(rxMob);
+
+    // create the tx and rx antennas and set the their dimensions
+    Ptr<PhasedArrayModel> txAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
+        "NumColumns",
+        UintegerValue(m_txAntennaElements),
+        "NumRows",
+        UintegerValue(m_txAntennaElements),
+        "AntennaElement",
+        PointerValue(CreateObject<IsotropicAntennaModel>()),
+        "NumVerticalPorts",
+        UintegerValue(m_txPorts),
+        "NumHorizontalPorts",
+        UintegerValue(m_txPorts));
+
+    Ptr<PhasedArrayModel> rxAntenna = CreateObjectWithAttributes<UniformPlanarArray>(
+        "NumColumns",
+        UintegerValue(m_rxAntennaElements),
+        "NumRows",
+        UintegerValue(m_rxAntennaElements),
+        "AntennaElement",
+        PointerValue(CreateObject<IsotropicAntennaModel>()),
+        "NumVerticalPorts",
+        UintegerValue(m_rxPorts),
+        "NumHorizontalPorts",
+        UintegerValue(m_rxPorts));
+
+    // check if the channel matrix is correctly updated
+
+    // compute the channel matrix for the first time
+    Simulator::Schedule(MilliSeconds(1),
+                        &ThreeGppAntennaSetupChangedTest::DoGetChannel,
+                        this,
+                        channelModel,
+                        txMob,
+                        rxMob,
+                        txAntenna,
+                        rxAntenna,
+                        true);
+
+    // call GetChannel before the update period is exceeded, the channel matrix
+    // should not be updated
+    Simulator::Schedule(MilliSeconds(2),
+                        &ThreeGppAntennaSetupChangedTest::DoGetChannel,
+                        this,
+                        channelModel,
+                        txMob,
+                        rxMob,
+                        txAntenna,
+                        rxAntenna,
+                        false);
+
+    // after changing the number of antenna ports, the channel matrix
+    // should be recomputed
+    Simulator::Schedule(MilliSeconds(3),
+                        [&txAntenna]() { txAntenna->SetNumRows(txAntenna->GetNumRows() + 1); });
+    Simulator::Schedule(MilliSeconds(4),
+                        &ThreeGppAntennaSetupChangedTest::DoGetChannel,
+                        this,
+                        channelModel,
+                        txMob,
+                        rxMob,
+                        txAntenna,
+                        rxAntenna,
+                        true);
+
+    // after recomputing it once, the channel matrix should be cached
+    Simulator::Schedule(MilliSeconds(5),
+                        &ThreeGppAntennaSetupChangedTest::DoGetChannel,
+                        this,
+                        channelModel,
+                        txMob,
+                        rxMob,
+                        txAntenna,
+                        rxAntenna,
+                        false);
+
+    // after recomputing it once, the channel matrix should be cached
+    Simulator::Schedule(MilliSeconds(6),
+                        [&rxAntenna]() { rxAntenna->SetNumRows(rxAntenna->GetNumRows() + 1); });
+    Simulator::Schedule(MilliSeconds(7),
+                        &ThreeGppAntennaSetupChangedTest::DoGetChannel,
+                        this,
+                        channelModel,
+                        txMob,
+                        rxMob,
+                        txAntenna,
+                        rxAntenna,
+                        true);
+
+    // after recomputing it once, the channel matrix should be cached
+    Simulator::Schedule(MilliSeconds(8),
+                        &ThreeGppAntennaSetupChangedTest::DoGetChannel,
+                        this,
+                        channelModel,
+                        txMob,
+                        rxMob,
+                        txAntenna,
+                        rxAntenna,
+                        false);
+
+    Simulator::Run();
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup spectrum-tests
  * \brief A structure that holds the parameters for the function
  * CheckLongTermUpdate. In this way the problem with the limited
  * number of parameters of method Schedule is avoided.
@@ -1228,22 +1456,27 @@
 };
 
 ThreeGppChannelTestSuite::ThreeGppChannelTestSuite()
-    : TestSuite("three-gpp-channel", UNIT)
+    : TestSuite("three-gpp-channel", Type::UNIT)
 {
-    AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 1, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 1, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 2, 2), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 4, 2, 2), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 2, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 1, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 1, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 2, 2), TestCase::QUICK);
-    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 2, 2), TestCase::QUICK);
-    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 4, 1, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 4, 2, 2), TestCase::QUICK);
-    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 2, 2, 2), TestCase::QUICK);
-    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 2, 2, 1), TestCase::QUICK);
-    AddTestCase(new ThreeGppCalcLongTermMultiPortTest(), TestCase::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 1, 1), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 1, 1), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixComputationTest(2, 2, 2, 2), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 4, 2, 2), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixComputationTest(4, 2, 2, 1), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 1, 1), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 1, 1), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 4, 2, 2), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppChannelMatrixUpdateTest(2, 2, 2, 2), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppAntennaSetupChangedTest(), TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 4, 1, 1),
+                TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 4, 2, 2),
+                TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 2, 2, 2),
+                TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppSpectrumPropagationLossModelTest(4, 2, 2, 1),
+                TestCase::Duration::QUICK);
+    AddTestCase(new ThreeGppCalcLongTermMultiPortTest(), TestCase::Duration::QUICK);
 
     /**
      *  The TX and RX antennas are configured face-to-face.
@@ -1263,7 +1496,7 @@
                                                  MimoPolarizationAntennaParams(false, 0, M_PI),
                                                  testChannel1,
                                                  0.9),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     /**
      *  The TX and RX antennas are configured face-to-face.
@@ -1282,7 +1515,7 @@
                                          MimoPolarizationAntennaParams(false, 0, M_PI),
                                          {5, 5, 3, 3, 5, 5, 3, 3, 3, 3, -5, -5, 3, 3, -5, -5},
                                          0.8),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     /**
      *  The TX and RX antennas are configured face-to-face.
@@ -1301,7 +1534,7 @@
                                          MimoPolarizationAntennaParams(false, 0, M_PI),
                                          {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -4, -4, 4, 4, -4, -4},
                                          0.7),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     /**
      *  The TX and RX antennas are configured face-to-face.
@@ -1320,7 +1553,7 @@
                     MimoPolarizationAntennaParams(false, 0, M_PI),
                     {0, 0, 5.8, 5.8, 0, 0, 5.8, 5.8, 5.9, 5.9, 0, 0, 5.9, 5.9, 0, 0},
                     0.9),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     /**
      *  The TX and RX antennas are face to face. We test the configuration of
@@ -1344,7 +1577,7 @@
                                          MimoPolarizationAntennaParams(false, 0, -(M_PI / 4) * 3),
                                          testChannel1,
                                          0.9),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     /**
      *  The TX and RX antenna have different height.
@@ -1379,7 +1612,7 @@
                      {-2.4, 4},
                      {-2.4, 4}},
                     0.5),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/tv-helper-distribution-test.cc ns-3.42/src/spectrum/test/tv-helper-distribution-test.cc
--- ns-3.41/src/spectrum/test/tv-helper-distribution-test.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/tv-helper-distribution-test.cc	2024-05-29 15:29:47.172073600 -0700
@@ -144,12 +144,13 @@
 };
 
 TvHelperDistributionTestSuite::TvHelperDistributionTestSuite()
-    : TestSuite("tv-helper-distribution", UNIT)
+    : TestSuite("tv-helper-distribution", Type::UNIT)
 {
     NS_LOG_INFO("creating TvHelperDistributionTestSuite");
     for (uint32_t maxNumTransmitters = 3; maxNumTransmitters <= 203; maxNumTransmitters += 10)
     {
-        AddTestCase(new TvHelperDistributionTestCase(maxNumTransmitters), TestCase::QUICK);
+        AddTestCase(new TvHelperDistributionTestCase(maxNumTransmitters),
+                    TestCase::Duration::QUICK);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/tv-spectrum-transmitter-test.cc ns-3.42/src/spectrum/test/tv-spectrum-transmitter-test.cc
--- ns-3.41/src/spectrum/test/tv-spectrum-transmitter-test.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/tv-spectrum-transmitter-test.cc	2024-05-29 15:29:47.172073600 -0700
@@ -181,7 +181,7 @@
 };
 
 TvSpectrumTransmitterTestSuite::TvSpectrumTransmitterTestSuite()
-    : TestSuite("tv-spectrum-transmitter", UNIT)
+    : TestSuite("tv-spectrum-transmitter", Type::UNIT)
 {
     NS_LOG_INFO("creating TvSpectrumTransmitterTestSuite");
     for (double startFreq = 100; startFreq < 1e15; startFreq *= 10)
@@ -194,7 +194,7 @@
                                                               bandwidth,
                                                               psd,
                                                               TvSpectrumTransmitter::TVTYPE_8VSB),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
             }
         }
     }
@@ -208,7 +208,7 @@
                                                               bandwidth,
                                                               psd,
                                                               TvSpectrumTransmitter::TVTYPE_COFDM),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
             }
         }
     }
@@ -222,7 +222,7 @@
                                                               bandwidth,
                                                               psd,
                                                               TvSpectrumTransmitter::TVTYPE_ANALOG),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
             }
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/spectrum/test/two-ray-splm-test-suite.cc ns-3.42/src/spectrum/test/two-ray-splm-test-suite.cc
--- ns-3.41/src/spectrum/test/two-ray-splm-test-suite.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/spectrum/test/two-ray-splm-test-suite.cc	2024-05-29 15:29:47.172073600 -0700
@@ -597,10 +597,10 @@
 };
 
 TwoRaySplmTestSuite::TwoRaySplmTestSuite()
-    : TestSuite("two-ray-splm-suite", UNIT)
+    : TestSuite("two-ray-splm-suite", Type::UNIT)
 {
     // Test the GetFtrFastFading function of the TwoRaySpectrumPropagationLossModel class
-    AddTestCase(new FtrFadingModelAverageTest, TestCase::QUICK);
+    AddTestCase(new FtrFadingModelAverageTest, TestCase::Duration::QUICK);
 
     // Test the CalcBeamformingGain function of the TwoRaySpectrumPropagationLossModel class
     auto iso = CreateObject<IsotropicAntennaModel>();
@@ -621,7 +621,7 @@
                                       0.0,
                                       -M_PI,
                                       0.0),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(iso,
                                       iso,
                                       4,
@@ -631,7 +631,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(iso,
                                       iso,
                                       16,
@@ -641,7 +641,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(16)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(iso,
                                       iso,
                                       64,
@@ -651,7 +651,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(64)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(iso,
                                       iso,
                                       4,
@@ -661,7 +661,7 @@
                                       0.0,
                                       -M_PI,
                                       2 * 10 * log10(4)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(iso,
                                       iso,
                                       16,
@@ -671,7 +671,7 @@
                                       0.0,
                                       -M_PI,
                                       2 * 10 * log10(16)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(iso,
                                       iso,
                                       64,
@@ -681,7 +681,7 @@
                                       0.0,
                                       -M_PI,
                                       2 * 10 * log10(64)),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       iso,
                                       1,
@@ -691,7 +691,7 @@
                                       0.0,
                                       -M_PI,
                                       maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       iso,
                                       4,
@@ -701,7 +701,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(4) + maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       iso,
                                       16,
@@ -711,7 +711,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(16) + maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       iso,
                                       64,
@@ -721,7 +721,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(64) + maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       1,
@@ -731,7 +731,7 @@
                                       0.0,
                                       -M_PI,
                                       2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       4,
@@ -741,7 +741,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(4) + 2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       16,
@@ -751,7 +751,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(16) + 2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       64,
@@ -761,7 +761,7 @@
                                       0.0,
                                       -M_PI,
                                       10 * log10(64) + 2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       4,
@@ -771,7 +771,7 @@
                                       0.0,
                                       -M_PI,
                                       2 * 10 * log10(4) + 2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       16,
@@ -781,7 +781,7 @@
                                       0.0,
                                       -M_PI,
                                       2 * 10 * log10(16) + 2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new ArrayResponseTest(tgpp,
                                       tgpp,
                                       64,
@@ -791,44 +791,52 @@
                                       0.0,
                                       -M_PI,
                                       2 * 10 * log10(64) + 2 * maxTgppGain),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Deploy 2 squared antenna arrays which face each other. Steer their beam towards the boresight
     // and check the overall resulting channel gain. SE = single element radiation pattern, N =
     // number of radiating elements, Fc = carrier frequency, Scen = 3GPP scenario
     //                                     SE tx,   SE rx, N tx, N rx,    Fc,    Scen
-    AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 10e9, "RMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 10e9, "RMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 10e9, "RMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 10e9, "RMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 10e9, "UMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 10e9, "UMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 10e9, "UMa"), TestCase::EXTENSIVE);
-    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 10e9, "UMa"), TestCase::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 10e9, "RMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 10e9, "RMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 10e9, "RMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 10e9, "RMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 10e9, "UMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 10e9, "UMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 10e9, "UMa"),
+                TestCase::Duration::EXTENSIVE);
+    AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 10e9, "UMa"),
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 60e9, "UMi-StreetCanyon"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 60e9, "UMi-StreetCanyon"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 60e9, "UMi-StreetCanyon"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 60e9, "UMi-StreetCanyon"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 60e9, "InH-OfficeOpen"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 60e9, "InH-OfficeOpen"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 60e9, "InH-OfficeOpen"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 60e9, "InH-OfficeOpen"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(iso, iso, 1, 1, 100e9, "InH-OfficeMixed"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 1, 1, 100e9, "InH-OfficeMixed"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(iso, iso, 4, 4, 100e9, "InH-OfficeMixed"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
     AddTestCase(new OverallGainAverageTest(tgpp, tgpp, 4, 4, 100e9, "InH-OfficeMixed"),
-                TestCase::EXTENSIVE);
+                TestCase::Duration::EXTENSIVE);
 }
 
 // Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/helper/file-helper.cc ns-3.42/src/stats/helper/file-helper.cc
--- ns-3.41/src/stats/helper/file-helper.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/stats/helper/file-helper.cc	2024-05-29 15:29:47.172073600 -0700
@@ -476,7 +476,8 @@
     AddTimeSeriesAdaptor(probeContext);
 
     // Connect the probe to the adaptor.
-    if (m_probeMap[probeName].second == "ns3::DoubleProbe")
+    if (m_probeMap[probeName].second == "ns3::DoubleProbe" ||
+        m_probeMap[probeName].second == "ns3::TimeProbe")
     {
         m_probeMap[probeName].first->TraceConnectWithoutContext(
             probeTraceSource,
@@ -490,28 +491,11 @@
             MakeCallback(&TimeSeriesAdaptor::TraceSinkBoolean,
                          m_timeSeriesAdaptorMap[probeContext]));
     }
-    else if (m_probeMap[probeName].second == "ns3::PacketProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
+    else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe" ||
+             m_probeMap[probeName].second == "ns3::PacketProbe" ||
+             m_probeMap[probeName].second == "ns3::ApplicationPacketProbe" ||
+             m_probeMap[probeName].second == "ns3::Ipv4PacketProbe" ||
+             m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
     {
         m_probeMap[probeName].first->TraceConnectWithoutContext(
             probeTraceSource,
@@ -532,20 +516,6 @@
             MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger16,
                          m_timeSeriesAdaptorMap[probeContext]));
     }
-    else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::TimeProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkDouble,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
     else
     {
         NS_FATAL_ERROR("Unknown probe type " << m_probeMap[probeName].second
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/helper/gnuplot-helper.cc ns-3.42/src/stats/helper/gnuplot-helper.cc
--- ns-3.41/src/stats/helper/gnuplot-helper.cc	2024-02-09 14:44:08.501794300 -0800
+++ ns-3.42/src/stats/helper/gnuplot-helper.cc	2024-05-29 15:29:47.172073600 -0700
@@ -333,7 +333,8 @@
     AddTimeSeriesAdaptor(probeContext);
 
     // Connect the probe to the adaptor.
-    if (m_probeMap[probeName].second == "ns3::DoubleProbe")
+    if (m_probeMap[probeName].second == "ns3::DoubleProbe" ||
+        m_probeMap[probeName].second == "ns3::TimeProbe")
     {
         m_probeMap[probeName].first->TraceConnectWithoutContext(
             probeTraceSource,
@@ -347,28 +348,11 @@
             MakeCallback(&TimeSeriesAdaptor::TraceSinkBoolean,
                          m_timeSeriesAdaptorMap[probeContext]));
     }
-    else if (m_probeMap[probeName].second == "ns3::PacketProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::ApplicationPacketProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::Ipv4PacketProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
+    else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe" ||
+             m_probeMap[probeName].second == "ns3::PacketProbe" ||
+             m_probeMap[probeName].second == "ns3::ApplicationPacketProbe" ||
+             m_probeMap[probeName].second == "ns3::Ipv4PacketProbe" ||
+             m_probeMap[probeName].second == "ns3::Ipv6PacketProbe")
     {
         m_probeMap[probeName].first->TraceConnectWithoutContext(
             probeTraceSource,
@@ -389,20 +373,6 @@
             MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger16,
                          m_timeSeriesAdaptorMap[probeContext]));
     }
-    else if (m_probeMap[probeName].second == "ns3::Uinteger32Probe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkUinteger32,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
-    else if (m_probeMap[probeName].second == "ns3::TimeProbe")
-    {
-        m_probeMap[probeName].first->TraceConnectWithoutContext(
-            probeTraceSource,
-            MakeCallback(&TimeSeriesAdaptor::TraceSinkDouble,
-                         m_timeSeriesAdaptorMap[probeContext]));
-    }
     else
     {
         NS_FATAL_ERROR("Unknown probe type " << m_probeMap[probeName].second
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/model/omnet-data-output.cc ns-3.42/src/stats/model/omnet-data-output.cc
--- ns-3.41/src/stats/model/omnet-data-output.cc	2024-02-09 14:44:08.505794300 -0800
+++ ns-3.42/src/stats/model/omnet-data-output.cc	2024-05-29 15:29:47.176073800 -0700
@@ -77,7 +77,8 @@
 
     for (auto it = s.begin(); it != s.end(); it++)
     {
-        if ((*it == '.') && (decimalPtSeen))
+        if ((*it == '.' && decimalPtSeen) || (*it == 'e' && exponentSeen) ||
+            (*it == '-' && it != s.begin() && last != 'e'))
         {
             return false;
         }
@@ -85,19 +86,11 @@
         {
             decimalPtSeen = true;
         }
-        else if ((*it == 'e') && exponentSeen)
-        {
-            return false;
-        }
         else if (*it == 'e')
         {
             exponentSeen = true;
             decimalPtSeen = false;
         }
-        else if (*it == '-' && it != s.begin() && last != 'e')
-        {
-            return false;
-        }
 
         last = *it;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/test/average-test-suite.cc ns-3.42/src/stats/test/average-test-suite.cc
--- ns-3.41/src/stats/test/average-test-suite.cc	2024-02-09 14:44:08.505794300 -0800
+++ ns-3.42/src/stats/test/average-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -317,11 +317,11 @@
 };
 
 AverageTestSuite::AverageTestSuite()
-    : TestSuite("average", UNIT)
+    : TestSuite("average", Type::UNIT)
 {
-    AddTestCase(new OneIntegerAverageTestCase, TestCase::QUICK);
-    AddTestCase(new FiveIntegersAverageTestCase, TestCase::QUICK);
-    AddTestCase(new FiveDoublesAverageTestCase, TestCase::QUICK);
+    AddTestCase(new OneIntegerAverageTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new FiveIntegersAverageTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new FiveDoublesAverageTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/test/basic-data-calculators-test-suite.cc ns-3.42/src/stats/test/basic-data-calculators-test-suite.cc
--- ns-3.41/src/stats/test/basic-data-calculators-test-suite.cc	2024-02-09 14:44:08.505794300 -0800
+++ ns-3.42/src/stats/test/basic-data-calculators-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -261,11 +261,11 @@
 };
 
 BasicDataCalculatorsTestSuite::BasicDataCalculatorsTestSuite()
-    : TestSuite("basic-data-calculators", UNIT)
+    : TestSuite("basic-data-calculators", Type::UNIT)
 {
-    AddTestCase(new OneIntegerTestCase, TestCase::QUICK);
-    AddTestCase(new FiveIntegersTestCase, TestCase::QUICK);
-    AddTestCase(new FiveDoublesTestCase, TestCase::QUICK);
+    AddTestCase(new OneIntegerTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new FiveIntegersTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new FiveDoublesTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/test/double-probe-test-suite.cc ns-3.42/src/stats/test/double-probe-test-suite.cc
--- ns-3.41/src/stats/test/double-probe-test-suite.cc	2024-02-09 14:44:08.505794300 -0800
+++ ns-3.42/src/stats/test/double-probe-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -210,9 +210,9 @@
 };
 
 ProbeTestSuite::ProbeTestSuite()
-    : TestSuite("double-probe", UNIT)
+    : TestSuite("double-probe", Type::UNIT)
 {
-    AddTestCase(new ProbeTestCase1, TestCase::QUICK);
+    AddTestCase(new ProbeTestCase1, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/stats/test/histogram-test-suite.cc ns-3.42/src/stats/test/histogram-test-suite.cc
--- ns-3.41/src/stats/test/histogram-test-suite.cc	2024-02-09 14:44:08.505794300 -0800
+++ ns-3.42/src/stats/test/histogram-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -83,9 +83,9 @@
 };
 
 HistogramTestSuite::HistogramTestSuite()
-    : TestSuite("histogram", UNIT)
+    : TestSuite("histogram", Type::UNIT)
 {
-    AddTestCase(new HistogramTestCase, TestCase::QUICK);
+    AddTestCase(new HistogramTestCase, TestCase::Duration::QUICK);
 }
 
 static HistogramTestSuite g_HistogramTestSuite; //!< Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/tap-bridge/examples/tap-csma-virtual-machine.py ns-3.42/src/tap-bridge/examples/tap-csma-virtual-machine.py
--- ns-3.41/src/tap-bridge/examples/tap-csma-virtual-machine.py	2024-02-09 14:44:08.505794300 -0800
+++ ns-3.42/src/tap-bridge/examples/tap-csma-virtual-machine.py	2024-05-29 15:29:47.176073800 -0700
@@ -29,24 +29,22 @@
 
 
 def main(argv):
-    ns.core.CommandLine().Parse(argv)
+    ns.CommandLine().Parse(argv)
 
     #
     # We are interacting with the outside, real, world.  This means we have to
     # interact in real-time and therefore we have to use the real-time simulator
     # and take the time to calculate checksums.
     #
-    ns.core.GlobalValue.Bind(
-        "SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")
-    )
-    ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue(True))
+    ns.GlobalValue.Bind("SimulatorImplementationType", ns.StringValue("ns3::RealtimeSimulatorImpl"))
+    ns.GlobalValue.Bind("ChecksumEnabled", ns.BooleanValue(True))
 
     #
     # Create two ghost nodes.  The first will represent the virtual machine host
     # on the left side of the network; and the second will represent the VM on
     # the right side.
     #
-    nodes = ns.network.NodeContainer()
+    nodes = ns.NodeContainer()
     nodes.Create(2)
 
     #
@@ -54,7 +52,7 @@
     # devices installed on both of the nodes.  The data rate and delay for the
     # channel can be set through the command-line parser.
     #
-    csma = ns.csma.CsmaHelper()
+    csma = ns.CsmaHelper()
     devices = csma.Install(nodes)
 
     #
@@ -65,24 +63,24 @@
     # only see traffic from one other device on that bridge.  That is the case
     # for this configuration.
     #
-    tapBridge = ns.tap_bridge.TapBridgeHelper()
-    tapBridge.SetAttribute("Mode", ns.core.StringValue("UseLocal"))
-    tapBridge.SetAttribute("DeviceName", ns.core.StringValue("tap-left"))
+    tapBridge = ns.TapBridgeHelper()
+    tapBridge.SetAttribute("Mode", ns.StringValue("UseLocal"))
+    tapBridge.SetAttribute("DeviceName", ns.StringValue("tap-left"))
     tapBridge.Install(nodes.Get(0), devices.Get(0))
 
     #
     # Connect the right side tap to the right side wifi device on the right-side
     # ghost node.
     #
-    tapBridge.SetAttribute("DeviceName", ns.core.StringValue("tap-right"))
+    tapBridge.SetAttribute("DeviceName", ns.StringValue("tap-right"))
     tapBridge.Install(nodes.Get(1), devices.Get(1))
 
     #
     # Run the simulation for ten minutes to give the user time to play around
     #
-    ns.core.Simulator.Stop(ns.core.Seconds(600))
-    ns.core.Simulator.Run()  # signal_check_frequency = -1
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Stop(ns.Seconds(600))
+    ns.Simulator.Run()  # signal_check_frequency = -1
+    ns.Simulator.Destroy()
     return 0
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/tap-bridge/examples/tap-wifi-virtual-machine.py ns-3.42/src/tap-bridge/examples/tap-wifi-virtual-machine.py
--- ns-3.41/src/tap-bridge/examples/tap-wifi-virtual-machine.py	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/tap-bridge/examples/tap-wifi-virtual-machine.py	2024-05-29 15:29:47.176073800 -0700
@@ -29,46 +29,44 @@
 
 
 def main(argv):
-    ns.core.CommandLine().Parse(argv)
+    ns.CommandLine().Parse(argv)
 
     #
     # We are interacting with the outside, real, world.  This means we have to
     # interact in real-time and therefore we have to use the real-time simulator
     # and take the time to calculate checksums.
     #
-    ns.core.GlobalValue.Bind(
-        "SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")
-    )
-    ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue(True))
+    ns.GlobalValue.Bind("SimulatorImplementationType", ns.StringValue("ns3::RealtimeSimulatorImpl"))
+    ns.GlobalValue.Bind("ChecksumEnabled", ns.BooleanValue(True))
 
     #
     # Create two ghost nodes.  The first will represent the virtual machine host
     # on the left side of the network; and the second will represent the VM on
     # the right side.
     #
-    nodes = ns.network.NodeContainer()
+    nodes = ns.NodeContainer()
     nodes.Create(2)
 
     #
     # We're going to use 802.11 A so set up a wifi helper to reflect that.
     #
-    wifi = ns.wifi.WifiHelper()
-    wifi.SetStandard(ns.wifi.WIFI_STANDARD_80211a)
+    wifi = ns.WifiHelper()
+    wifi.SetStandard(ns.WIFI_STANDARD_80211a)
     wifi.SetRemoteStationManager(
-        "ns3::ConstantRateWifiManager", "DataMode", ns.core.StringValue("OfdmRate54Mbps")
+        "ns3::ConstantRateWifiManager", "DataMode", ns.StringValue("OfdmRate54Mbps")
     )
 
     #
     # No reason for pesky access points, so we'll use an ad-hoc network.
     #
-    wifiMac = ns.wifi.WifiMacHelper()
+    wifiMac = ns.WifiMacHelper()
     wifiMac.SetType("ns3::AdhocWifiMac")
 
     #
     # Configure the physical layer.
     #
-    wifiChannel = ns.wifi.YansWifiChannelHelper.Default()
-    wifiPhy = ns.wifi.YansWifiPhyHelper()
+    wifiChannel = ns.YansWifiChannelHelper.Default()
+    wifiPhy = ns.YansWifiPhyHelper()
     wifiPhy.SetChannel(wifiChannel.Create())
 
     #
@@ -80,10 +78,10 @@
     # We need location information since we are talking about wifi, so add a
     # constant position to the ghost nodes.
     #
-    mobility = ns.mobility.MobilityHelper()
-    positionAlloc = ns.mobility.ListPositionAllocator()
-    positionAlloc.Add(ns.core.Vector(0.0, 0.0, 0.0))
-    positionAlloc.Add(ns.core.Vector(5.0, 0.0, 0.0))
+    mobility = ns.MobilityHelper()
+    positionAlloc = ns.ListPositionAllocator()
+    positionAlloc.Add(ns.Vector(0.0, 0.0, 0.0))
+    positionAlloc.Add(ns.Vector(5.0, 0.0, 0.0))
     mobility.SetPositionAllocator(positionAlloc)
     mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel")
     mobility.Install(nodes)
@@ -96,24 +94,24 @@
     # only see traffic from one other device on that bridge.  That is the case
     # for this configuration.
     #
-    tapBridge = ns.tap_bridge.TapBridgeHelper()
-    tapBridge.SetAttribute("Mode", ns.core.StringValue("UseLocal"))
-    tapBridge.SetAttribute("DeviceName", ns.core.StringValue("tap-left"))
+    tapBridge = ns.TapBridgeHelper()
+    tapBridge.SetAttribute("Mode", ns.StringValue("UseLocal"))
+    tapBridge.SetAttribute("DeviceName", ns.StringValue("tap-left"))
     tapBridge.Install(nodes.Get(0), devices.Get(0))
 
     #
     # Connect the right side tap to the right side wifi device on the right-side
     # ghost node.
     #
-    tapBridge.SetAttribute("DeviceName", ns.core.StringValue("tap-right"))
+    tapBridge.SetAttribute("DeviceName", ns.StringValue("tap-right"))
     tapBridge.Install(nodes.Get(1), devices.Get(1))
 
     #
     # Run the simulation for ten minutes to give the user time to play around
     #
-    ns.core.Simulator.Stop(ns.core.Seconds(600))
-    ns.core.Simulator.Run()  # signal_check_frequency = -1
-    ns.core.Simulator.Destroy()
+    ns.Simulator.Stop(ns.Seconds(600))
+    ns.Simulator.Run()  # signal_check_frequency = -1
+    ns.Simulator.Destroy()
     return 0
 
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/tap-bridge/model/tap-bridge.cc ns-3.42/src/tap-bridge/model/tap-bridge.cc
--- ns-3.41/src/tap-bridge/model/tap-bridge.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/tap-bridge/model/tap-bridge.cc	2024-05-29 15:29:47.176073800 -0700
@@ -608,7 +608,7 @@
         // an "ancillary element" but the msghdr uses the control message termimology
         // so we call it "control."
         //
-        size_t msg_size = sizeof(int);
+        constexpr size_t msg_size = sizeof(int);
         char control[CMSG_SPACE(msg_size)];
 
         //
@@ -799,7 +799,7 @@
         //
         // Packets we are going to forward should not be from a broadcast src
         //
-        NS_ASSERT_MSG(Mac48Address::ConvertFrom(src) != Mac48Address("ff:ff:ff:ff:ff:ff"),
+        NS_ASSERT_MSG(Mac48Address::ConvertFrom(src) != Mac48Address::GetBroadcast(),
                       "TapBridge::ForwardToBridgedDevice:  Source addr is broadcast");
         if (!m_ns3AddressRewritten)
         {
@@ -1156,7 +1156,7 @@
 TapBridge::GetBroadcast() const
 {
     NS_LOG_FUNCTION(this);
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/tap-bridge/model/tap-creator.cc ns-3.42/src/tap-bridge/model/tap-creator.cc
--- ns-3.41/src/tap-bridge/model/tap-creator.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/tap-bridge/model/tap-creator.cc	2024-05-29 15:29:47.176073800 -0700
@@ -138,7 +138,7 @@
     // an "ancillary element" but the msghdr uses the control message termimology
     // so we call it "control."
     //
-    size_t msg_size = sizeof(int);
+    constexpr size_t msg_size = sizeof(int);
     char control[CMSG_SPACE(msg_size)];
 
     //
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/csma-system-test-suite.cc ns-3.42/src/test/csma-system-test-suite.cc
--- ns-3.41/src/test/csma-system-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/csma-system-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -1243,16 +1243,16 @@
 };
 
 CsmaSystemTestSuite::CsmaSystemTestSuite()
-    : TestSuite("csma-system", UNIT)
+    : TestSuite("csma-system", Type::UNIT)
 {
-    AddTestCase(new CsmaBridgeTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaBroadcastTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaMulticastTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaOneSubnetTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaPacketSocketTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaPingTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaRawIpSocketTestCase, TestCase::QUICK);
-    AddTestCase(new CsmaStarTestCase, TestCase::QUICK);
+    AddTestCase(new CsmaBridgeTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaBroadcastTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaMulticastTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaOneSubnetTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaPacketSocketTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaPingTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaRawIpSocketTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new CsmaStarTestCase, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tc/fq-cobalt-queue-disc-test-suite.cc ns-3.42/src/test/ns3tc/fq-cobalt-queue-disc-test-suite.cc
--- ns-3.41/src/test/ns3tc/fq-cobalt-queue-disc-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tc/fq-cobalt-queue-disc-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -1718,16 +1718,16 @@
 };
 
 FqCobaltQueueDiscTestSuite::FqCobaltQueueDiscTestSuite()
-    : TestSuite("fq-cobalt-queue-disc", UNIT)
+    : TestSuite("fq-cobalt-queue-disc", Type::UNIT)
 {
-    AddTestCase(new FqCobaltQueueDiscNoSuitableFilter, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscDeficit, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscTCPFlowsSeparation, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscUDPFlowsSeparation, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscEcnMarking, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscSetLinearProbing, TestCase::QUICK);
-    AddTestCase(new FqCobaltQueueDiscL4sMode, TestCase::QUICK);
+    AddTestCase(new FqCobaltQueueDiscNoSuitableFilter, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscDeficit, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscTCPFlowsSeparation, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscUDPFlowsSeparation, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscEcnMarking, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscSetLinearProbing, TestCase::Duration::QUICK);
+    AddTestCase(new FqCobaltQueueDiscL4sMode, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tc/fq-codel-queue-disc-test-suite.cc ns-3.42/src/test/ns3tc/fq-codel-queue-disc-test-suite.cc
--- ns-3.41/src/test/ns3tc/fq-codel-queue-disc-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tc/fq-codel-queue-disc-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -1768,16 +1768,16 @@
 };
 
 FqCoDelQueueDiscTestSuite::FqCoDelQueueDiscTestSuite()
-    : TestSuite("fq-codel-queue-disc", UNIT)
+    : TestSuite("fq-codel-queue-disc", Type::UNIT)
 {
-    AddTestCase(new FqCoDelQueueDiscNoSuitableFilter, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscDeficit, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscTCPFlowsSeparation, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscUDPFlowsSeparation, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscECNMarking, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscSetLinearProbing, TestCase::QUICK);
-    AddTestCase(new FqCoDelQueueDiscL4sMode, TestCase::QUICK);
+    AddTestCase(new FqCoDelQueueDiscNoSuitableFilter, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscDeficit, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscTCPFlowsSeparation, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscUDPFlowsSeparation, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscECNMarking, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscSetLinearProbing, TestCase::Duration::QUICK);
+    AddTestCase(new FqCoDelQueueDiscL4sMode, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tc/fq-pie-queue-disc-test-suite.cc ns-3.42/src/test/ns3tc/fq-pie-queue-disc-test-suite.cc
--- ns-3.41/src/test/ns3tc/fq-pie-queue-disc-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tc/fq-pie-queue-disc-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -1160,15 +1160,15 @@
 };
 
 FqPieQueueDiscTestSuite::FqPieQueueDiscTestSuite()
-    : TestSuite("fq-pie-queue-disc", UNIT)
+    : TestSuite("fq-pie-queue-disc", Type::UNIT)
 {
-    AddTestCase(new FqPieQueueDiscNoSuitableFilter, TestCase::QUICK);
-    AddTestCase(new FqPieQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::QUICK);
-    AddTestCase(new FqPieQueueDiscDeficit, TestCase::QUICK);
-    AddTestCase(new FqPieQueueDiscTCPFlowsSeparation, TestCase::QUICK);
-    AddTestCase(new FqPieQueueDiscUDPFlowsSeparation, TestCase::QUICK);
-    AddTestCase(new FqPieQueueDiscSetLinearProbing, TestCase::QUICK);
-    AddTestCase(new FqPieQueueDiscL4sMode, TestCase::QUICK);
+    AddTestCase(new FqPieQueueDiscNoSuitableFilter, TestCase::Duration::QUICK);
+    AddTestCase(new FqPieQueueDiscIPFlowsSeparationAndPacketLimit, TestCase::Duration::QUICK);
+    AddTestCase(new FqPieQueueDiscDeficit, TestCase::Duration::QUICK);
+    AddTestCase(new FqPieQueueDiscTCPFlowsSeparation, TestCase::Duration::QUICK);
+    AddTestCase(new FqPieQueueDiscUDPFlowsSeparation, TestCase::Duration::QUICK);
+    AddTestCase(new FqPieQueueDiscSetLinearProbing, TestCase::Duration::QUICK);
+    AddTestCase(new FqPieQueueDiscL4sMode, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc ns-3.42/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc
--- ns-3.41/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tc/pfifo-fast-queue-disc-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -397,12 +397,12 @@
 };
 
 PfifoFastQueueDiscTestSuite::PfifoFastQueueDiscTestSuite()
-    : TestSuite("pfifo-fast-queue-disc", UNIT)
+    : TestSuite("pfifo-fast-queue-disc", Type::UNIT)
 {
-    AddTestCase(new PfifoFastQueueDiscTosPrioritization, TestCase::QUICK);
-    AddTestCase(new PfifoFastQueueDiscDscpPrioritization, TestCase::QUICK);
-    AddTestCase(new PfifoFastQueueDiscOverflow, TestCase::QUICK);
-    AddTestCase(new PfifoFastQueueDiscNoPriority, TestCase::QUICK);
+    AddTestCase(new PfifoFastQueueDiscTosPrioritization, TestCase::Duration::QUICK);
+    AddTestCase(new PfifoFastQueueDiscDscpPrioritization, TestCase::Duration::QUICK);
+    AddTestCase(new PfifoFastQueueDiscOverflow, TestCase::Duration::QUICK);
+    AddTestCase(new PfifoFastQueueDiscNoPriority, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tcp/ns3tcp-cubic-test-suite.cc ns-3.42/src/test/ns3tcp/ns3tcp-cubic-test-suite.cc
--- ns-3.41/src/test/ns3tcp/ns3tcp-cubic-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tcp/ns3tcp-cubic-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -79,9 +79,7 @@
 
 /**
  * \ingroup system-tests-tcp
- */
-
-/**
+ *
  * Add sample trace values to data structures
  * \param gnuplotTimeSeries Gnuplot data structure
  * \param timeSeries time series of cwnd changes
@@ -101,6 +99,7 @@
 }
 
 /**
+ * \ingroup system-tests-tcp
  * Test Cubic response
  */
 class Ns3TcpCubicTestCase : public TestCase
@@ -364,7 +363,7 @@
                               true,
                               "cwnd outside range");
         // Time just before a reduction does not have much variation
-        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(9), Seconds(9.7), 84, 89),
+        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(9), Seconds(9.6), 84, 89),
                               true,
                               "cwnd outside range");
     }
@@ -381,20 +380,20 @@
     }
     else if (m_prefix == "ns3-tcp-cubic-no-friendly")
     {
-        // Between time 12 and 16, cwnd should be fairly constant
+        // Between time 11 and 15, cwnd should be fairly constant
         // because without TCP friendliness, Cubic does not respond quickly
-        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(12), Seconds(16), 107, 123),
+        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(11), Seconds(15), 107, 123),
                               true,
                               "cwnd outside range");
-        // After time 19.5, cwnd should have grown much higher
-        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(19.5), Seconds(20), 180, 210),
+        // After time 17.5, cwnd should have grown much higher
+        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(17.5), Seconds(18.5), 170, 215),
                               true,
                               "cwnd outside range");
     }
     else if (m_prefix == "ns3-tcp-cubic-friendly")
     {
         // In contrast to previous case, cwnd should grow above 150 much sooner
-        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(12), Seconds(14), 150, 210),
+        NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(13), Seconds(15), 150, 210),
                               true,
                               "cwnd outside range");
     }
@@ -403,7 +402,7 @@
 }
 
 /**
- * \ingroup tcp-cubic-tests
+ * \ingroup system-tests-tcp
  * TestSuite for module tcp-cubic
  */
 class Ns3TcpCubicTestSuite : public TestSuite
@@ -413,7 +412,7 @@
 };
 
 Ns3TcpCubicTestSuite::Ns3TcpCubicTestSuite()
-    : TestSuite("ns3-tcp-cubic", UNIT)
+    : TestSuite("ns3-tcp-cubic", Type::UNIT)
 {
     // Test Cubic with no fast convergence or TCP friendliness enabled
     // This results in a cwnd plot that has only the concave portion of
@@ -424,7 +423,7 @@
                                         false,
                                         MilliSeconds(5),
                                         false),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Cubic with fast convergence but no TCP friendliness enabled
     // This results in a cwnd plot that has concave and convex regions, as
@@ -435,7 +434,7 @@
                                         false,
                                         MilliSeconds(5),
                                         false),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Cubic with fast convergence but no TCP friendliness enabled
     // with a higher RTT (20ms) and a step change in capacity at time 10s.
@@ -446,7 +445,7 @@
                                         false,
                                         MilliSeconds(20),
                                         true),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // Test Cubic with fast convergence but with TCP friendliness enabled
     // with a higher RTT (20ms) and a step change in capacity at time 10s.
@@ -457,11 +456,10 @@
                                         true,
                                         MilliSeconds(20),
                                         true),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 /**
- * \ingroup tcp-cubic-tests
  * Static variable for test initialization
  */
 static Ns3TcpCubicTestSuite ns3TcpCubicTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tcp/ns3tcp-loss-test-suite.cc ns-3.42/src/test/ns3tcp/ns3tcp-loss-test-suite.cc
--- ns-3.41/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -510,23 +510,23 @@
 };
 
 Ns3TcpLossTestSuite::Ns3TcpLossTestSuite()
-    : TestSuite("ns3-tcp-loss", SYSTEM)
+    : TestSuite("ns3-tcp-loss", Type::SYSTEM)
 {
     // We can't use NS_TEST_SOURCEDIR variable here because we use subdirectories
     SetDataDir("src/test/ns3tcp/response-vectors");
     Packet::EnablePrinting(); // Enable packet metadata for all test cases
 
-    AddTestCase(new Ns3TcpLossTestCase("NewReno", 0), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("NewReno", 1), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("NewReno", 2), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("NewReno", 3), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("NewReno", 4), TestCase::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("NewReno", 0), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("NewReno", 1), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("NewReno", 2), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("NewReno", 3), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("NewReno", 4), TestCase::Duration::QUICK);
 
-    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 0), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 1), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 2), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 3), TestCase::QUICK);
-    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 4), TestCase::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 0), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 1), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 2), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 3), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpLossTestCase("WestwoodPlus", 4), TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tcp/ns3tcp-no-delay-test-suite.cc ns-3.42/src/test/ns3tcp/ns3tcp-no-delay-test-suite.cc
--- ns-3.41/src/test/ns3tcp/ns3tcp-no-delay-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tcp/ns3tcp-no-delay-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -223,10 +223,10 @@
 };
 
 Ns3TcpNoDelayTestSuite::Ns3TcpNoDelayTestSuite()
-    : TestSuite("ns3-tcp-no-delay", SYSTEM)
+    : TestSuite("ns3-tcp-no-delay", Type::SYSTEM)
 {
-    AddTestCase(new Ns3TcpNoDelayTestCase(true), TestCase::QUICK);
-    AddTestCase(new Ns3TcpNoDelayTestCase(false), TestCase::QUICK);
+    AddTestCase(new Ns3TcpNoDelayTestCase(true), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpNoDelayTestCase(false), TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tcp/ns3tcp-socket-test-suite.cc ns-3.42/src/test/ns3tcp/ns3tcp-socket-test-suite.cc
--- ns-3.41/src/test/ns3tcp/ns3tcp-socket-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tcp/ns3tcp-socket-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -309,10 +309,10 @@
 };
 
 Ns3TcpSocketTestSuite::Ns3TcpSocketTestSuite()
-    : TestSuite("ns3-tcp-socket", SYSTEM)
+    : TestSuite("ns3-tcp-socket", Type::SYSTEM)
 {
-    AddTestCase(new Ns3TcpSocketTestCaseP2P, TestCase::QUICK);
-    AddTestCase(new Ns3TcpSocketTestCaseCsma, TestCase::QUICK);
+    AddTestCase(new Ns3TcpSocketTestCaseP2P, TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpSocketTestCaseCsma, TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3tcp/ns3tcp-state-test-suite.cc ns-3.42/src/test/ns3tcp/ns3tcp-state-test-suite.cc
--- ns-3.41/src/test/ns3tcp/ns3tcp-state-test-suite.cc	2024-02-09 14:44:08.525794500 -0800
+++ ns-3.42/src/test/ns3tcp/ns3tcp-state-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -531,21 +531,21 @@
 };
 
 Ns3TcpStateTestSuite::Ns3TcpStateTestSuite()
-    : TestSuite("ns3-tcp-state", SYSTEM)
+    : TestSuite("ns3-tcp-state", Type::SYSTEM)
 {
     // We can't use NS_TEST_SOURCEDIR variable here because we use subdirectories
     SetDataDir("src/test/ns3tcp/response-vectors");
     Packet::EnablePrinting(); // Enable packet metadata for all test cases
 
-    AddTestCase(new Ns3TcpStateTestCase(0), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(1), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(2), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(3), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(4), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(5), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(6), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(7), TestCase::QUICK);
-    AddTestCase(new Ns3TcpStateTestCase(8), TestCase::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(0), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(1), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(2), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(3), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(4), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(5), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(6), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(7), TestCase::Duration::QUICK);
+    AddTestCase(new Ns3TcpStateTestCase(8), TestCase::Duration::QUICK);
 }
 
 /// Do not forget to allocate an instance of this TestSuite.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc ns-3.42/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc
--- ns-3.41/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc	2024-02-09 14:44:08.529794500 -0800
+++ ns-3.42/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -206,9 +206,9 @@
 
     // The packet source is an on-off application on the AP device
     InetSocketAddress dest(staNodeInterface.GetAddress(0), udpPort);
-    dest.SetTos(m_tos);
     OnOffHelper onoff("ns3::UdpSocketFactory", dest);
     onoff.SetConstantRate(DataRate("5kbps"), 500);
+    onoff.SetAttribute("Tos", UintegerValue(m_tos));
     ApplicationContainer sourceApp = onoff.Install(ap.Get(0));
     sourceApp.Start(Seconds(1.0));
     sourceApp.Stop(Seconds(4.0));
@@ -333,12 +333,12 @@
 };
 
 WifiAcMappingTestSuite::WifiAcMappingTestSuite()
-    : TestSuite("wifi-ac-mapping", SYSTEM)
+    : TestSuite("wifi-ac-mapping", Type::SYSTEM)
 {
-    AddTestCase(new WifiAcMappingTest(0xb8, 2), TestCase::QUICK); // EF in AC_VI
-    AddTestCase(new WifiAcMappingTest(0x28, 1), TestCase::QUICK); // AF11 in AC_BK
-    AddTestCase(new WifiAcMappingTest(0x70, 0), TestCase::QUICK); // AF32 in AC_BE
-    AddTestCase(new WifiAcMappingTest(0xc0, 3), TestCase::QUICK); // CS7 in AC_VO
+    AddTestCase(new WifiAcMappingTest(0xb8, 2), TestCase::Duration::QUICK); // EF in AC_VI
+    AddTestCase(new WifiAcMappingTest(0x28, 1), TestCase::Duration::QUICK); // AF11 in AC_BK
+    AddTestCase(new WifiAcMappingTest(0x70, 0), TestCase::Duration::QUICK); // AF32 in AC_BE
+    AddTestCase(new WifiAcMappingTest(0xc0, 3), TestCase::Duration::QUICK); // CS7 in AC_VO
 }
 
 static WifiAcMappingTestSuite wifiAcMappingTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3wifi/wifi-issue-211-test-suite.cc ns-3.42/src/test/ns3wifi/wifi-issue-211-test-suite.cc
--- ns-3.41/src/test/ns3wifi/wifi-issue-211-test-suite.cc	2024-02-09 14:44:08.529794500 -0800
+++ ns-3.42/src/test/ns3wifi/wifi-issue-211-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -258,9 +258,9 @@
 };
 
 Issue211TestSuite::Issue211TestSuite()
-    : TestSuite("wifi-issue-211", UNIT)
+    : TestSuite("wifi-issue-211", Type::UNIT)
 {
-    AddTestCase(new Issue211Test, TestCase::QUICK);
+    AddTestCase(new Issue211Test, TestCase::Duration::QUICK);
 }
 
 static Issue211TestSuite g_issue211TestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/ns3wifi/wifi-msdu-aggregator-test-suite.cc ns-3.42/src/test/ns3wifi/wifi-msdu-aggregator-test-suite.cc
--- ns-3.41/src/test/ns3wifi/wifi-msdu-aggregator-test-suite.cc	2024-02-09 14:44:08.529794500 -0800
+++ ns-3.42/src/test/ns3wifi/wifi-msdu-aggregator-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -218,9 +218,9 @@
 };
 
 WifiMsduAggregatorTestSuite::WifiMsduAggregatorTestSuite()
-    : TestSuite("wifi-msdu-aggregator", SYSTEM)
+    : TestSuite("wifi-msdu-aggregator", Type::SYSTEM)
 {
-    AddTestCase(new WifiMsduAggregatorThroughputTest, TestCase::QUICK);
+    AddTestCase(new WifiMsduAggregatorThroughputTest, TestCase::Duration::QUICK);
 }
 
 static WifiMsduAggregatorTestSuite wifiMsduAggregatorTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/traced/traced-callback-typedef-test-suite.cc ns-3.42/src/test/traced/traced-callback-typedef-test-suite.cc
--- ns-3.41/src/test/traced/traced-callback-typedef-test-suite.cc	2024-02-09 14:44:08.529794500 -0800
+++ ns-3.42/src/test/traced/traced-callback-typedef-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -171,9 +171,9 @@
 TYPENAME(Ipv6L3Protocol::DropTracedCallback);
 TYPENAME(Ipv6L3Protocol::SentTracedCallback);
 TYPENAME(Ipv6L3Protocol::TxRxTracedCallback);
-TYPENAME(LrWpanMac::SentTracedCallback);
-TYPENAME(LrWpanMac::StateTracedCallback);
-TYPENAME(LrWpanPhy::StateTracedCallback);
+TYPENAME(lrwpan::LrWpanMac::SentTracedCallback);
+TYPENAME(lrwpan::LrWpanMac::StateTracedCallback);
+TYPENAME(lrwpan::LrWpanPhy::StateTracedCallback);
 TYPENAME(LteEnbMac::DlSchedulingTracedCallback);
 TYPENAME(LteEnbMac::UlSchedulingTracedCallback);
 TYPENAME(LteEnbPhy::ReportInterferenceTracedCallback);
@@ -382,11 +382,14 @@
 
     CHECK(Ipv6L3Protocol::TxRxTracedCallback, Ptr<const Packet>, Ptr<Ipv6>, uint32_t);
 
-    CHECK(LrWpanMac::SentTracedCallback, Ptr<const Packet>, uint8_t, uint8_t);
+    CHECK(lrwpan::LrWpanMac::SentTracedCallback, Ptr<const Packet>, uint8_t, uint8_t);
 
-    CHECK(LrWpanMac::StateTracedCallback, LrWpanMacState, LrWpanMacState);
+    CHECK(lrwpan::LrWpanMac::StateTracedCallback, lrwpan::MacState, lrwpan::MacState);
 
-    CHECK(LrWpanPhy::StateTracedCallback, Time, LrWpanPhyEnumeration, LrWpanPhyEnumeration);
+    CHECK(lrwpan::LrWpanPhy::StateTracedCallback,
+          Time,
+          lrwpan::PhyEnumeration,
+          lrwpan::PhyEnumeration);
 
     CHECK(LteEnbMac::DlSchedulingTracedCallback,
           uint32_t,
@@ -537,9 +540,9 @@
 };
 
 TracedCallbackTypedefTestSuite::TracedCallbackTypedefTestSuite()
-    : TestSuite("traced-callback-typedef", SYSTEM)
+    : TestSuite("traced-callback-typedef", Type::SYSTEM)
 {
-    AddTestCase(new TracedCallbackTypedefTestCase, TestCase::QUICK);
+    AddTestCase(new TracedCallbackTypedefTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/test/traced/traced-value-callback-typedef-test-suite.cc ns-3.42/src/test/traced/traced-value-callback-typedef-test-suite.cc
--- ns-3.41/src/test/traced/traced-value-callback-typedef-test-suite.cc	2024-02-09 14:44:08.529794500 -0800
+++ ns-3.42/src/test/traced/traced-value-callback-typedef-test-suite.cc	2024-05-29 15:29:47.176073800 -0700
@@ -259,9 +259,9 @@
 };
 
 TracedValueCallbackTestSuite::TracedValueCallbackTestSuite()
-    : TestSuite("traced-value-callback", UNIT)
+    : TestSuite("traced-value-callback", Type::UNIT)
 {
-    AddTestCase(new TracedValueCallbackTestCase, TestCase::QUICK);
+    AddTestCase(new TracedValueCallbackTestCase, TestCase::Duration::QUICK);
 }
 
 /// Static variable for test initialization
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/topology-read/test/rocketfuel-topology-reader-test-suite.cc ns-3.42/src/topology-read/test/rocketfuel-topology-reader-test-suite.cc
--- ns-3.41/src/topology-read/test/rocketfuel-topology-reader-test-suite.cc	2024-02-09 14:44:08.529794500 -0800
+++ ns-3.42/src/topology-read/test/rocketfuel-topology-reader-test-suite.cc	2024-05-29 15:29:47.180073700 -0700
@@ -145,10 +145,10 @@
 };
 
 RocketfuelTopologyReaderTestSuite::RocketfuelTopologyReaderTestSuite()
-    : TestSuite("rocketfuel-topology-reader", UNIT)
+    : TestSuite("rocketfuel-topology-reader", Type::UNIT)
 {
-    AddTestCase(new RocketfuelTopologyReaderWeightsTest(), TestCase::QUICK);
-    AddTestCase(new RocketfuelTopologyReaderMapsTest(), TestCase::QUICK);
+    AddTestCase(new RocketfuelTopologyReaderWeightsTest(), TestCase::Duration::QUICK);
+    AddTestCase(new RocketfuelTopologyReaderMapsTest(), TestCase::Duration::QUICK);
 }
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/examples/fqcodel-l4s-example.cc ns-3.42/src/traffic-control/examples/fqcodel-l4s-example.cc
--- ns-3.41/src/traffic-control/examples/fqcodel-l4s-example.cc	2024-02-09 14:44:08.533794600 -0800
+++ ns-3.42/src/traffic-control/examples/fqcodel-l4s-example.cc	2024-05-29 15:29:47.180073700 -0700
@@ -681,7 +681,7 @@
     }
     else
     {
-        NS_FATAL_ERROR("Fatal error:  scenario unavailble");
+        NS_FATAL_ERROR("Fatal error:  scenario unavailable");
     }
 
     std::ofstream pingOfStream;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/model/pie-queue-disc.cc ns-3.42/src/traffic-control/model/pie-queue-disc.cc
--- ns-3.41/src/traffic-control/model/pie-queue-disc.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/model/pie-queue-disc.cc	2024-05-29 15:29:47.184073700 -0700
@@ -297,15 +297,9 @@
     }
 
     // Safeguard PIE to be work conserving (Section 4.1 of RFC 8033)
-    if ((m_qDelayOld.GetSeconds() < (0.5 * m_qDelayRef.GetSeconds())) && (m_dropProb < 0.2))
-    {
-        return false;
-    }
-    else if (GetMaxSize().GetUnit() == QueueSizeUnit::BYTES && qSize <= 2 * m_meanPktSize)
-    {
-        return false;
-    }
-    else if (GetMaxSize().GetUnit() == QueueSizeUnit::PACKETS && qSize <= 2)
+    if ((m_qDelayOld.GetSeconds() < (0.5 * m_qDelayRef.GetSeconds()) && m_dropProb < 0.2) ||
+        (GetMaxSize().GetUnit() == QueueSizeUnit::BYTES && qSize <= 2 * m_meanPktSize) ||
+        (GetMaxSize().GetUnit() == QueueSizeUnit::PACKETS && qSize <= 2))
     {
         return false;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -419,8 +419,8 @@
 {
   public:
     AredQueueDiscTestSuite()
-        : TestSuite("adaptive-red-queue-disc", UNIT)
+        : TestSuite("adaptive-red-queue-disc", Type::UNIT)
     {
-        AddTestCase(new AredQueueDiscTestCase(), TestCase::QUICK);
+        AddTestCase(new AredQueueDiscTestCase(), TestCase::Duration::QUICK);
     }
 } g_aredQueueDiscTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/cobalt-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/cobalt-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/cobalt-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/cobalt-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -1196,21 +1196,21 @@
 {
   public:
     CobaltQueueDiscTestSuite()
-        : TestSuite("cobalt-queue-disc", UNIT)
+        : TestSuite("cobalt-queue-disc", Type::UNIT)
     {
         // Test 1: simple enqueue/dequeue with no drops
-        AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(PACKETS), TestCase::QUICK);
-        AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(BYTES), TestCase::QUICK);
+        AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(PACKETS), TestCase::Duration::QUICK);
+        AddTestCase(new CobaltQueueDiscBasicEnqueueDequeue(BYTES), TestCase::Duration::QUICK);
         // Test 2: Drop test
-        AddTestCase(new CobaltQueueDiscDropTest(), TestCase::QUICK);
+        AddTestCase(new CobaltQueueDiscDropTest(), TestCase::Duration::QUICK);
         // Test 3: Mark test
-        AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::QUICK);
-        AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::QUICK);
+        AddTestCase(new CobaltQueueDiscMarkTest(PACKETS), TestCase::Duration::QUICK);
+        AddTestCase(new CobaltQueueDiscMarkTest(BYTES), TestCase::Duration::QUICK);
         // Test 4: CE threshold marking test
-        AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::QUICK);
-        AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::QUICK);
+        AddTestCase(new CobaltQueueDiscCeThresholdTest(PACKETS), TestCase::Duration::QUICK);
+        AddTestCase(new CobaltQueueDiscCeThresholdTest(BYTES), TestCase::Duration::QUICK);
         // Test 4: Blue enhancement test
-        AddTestCase(new CobaltQueueDiscEnhancedBlueTest(PACKETS), TestCase::QUICK);
-        AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::QUICK);
+        AddTestCase(new CobaltQueueDiscEnhancedBlueTest(PACKETS), TestCase::Duration::QUICK);
+        AddTestCase(new CobaltQueueDiscEnhancedBlueTest(BYTES), TestCase::Duration::QUICK);
     }
 } g_cobaltQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/codel-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/codel-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/codel-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/codel-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -1329,23 +1329,27 @@
 {
   public:
     CoDelQueueDiscTestSuite()
-        : TestSuite("codel-queue-disc", UNIT)
+        : TestSuite("codel-queue-disc", Type::UNIT)
     {
         // Test 1: simple enqueue/dequeue with no drops
-        AddTestCase(new CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit::PACKETS), TestCase::QUICK);
-        AddTestCase(new CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit::BYTES), TestCase::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit::PACKETS),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicEnqueueDequeue(QueueSizeUnit::BYTES),
+                    TestCase::Duration::QUICK);
         // Test 2: enqueue with drops due to queue overflow
-        AddTestCase(new CoDelQueueDiscBasicOverflow(QueueSizeUnit::PACKETS), TestCase::QUICK);
-        AddTestCase(new CoDelQueueDiscBasicOverflow(QueueSizeUnit::BYTES), TestCase::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicOverflow(QueueSizeUnit::PACKETS),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicOverflow(QueueSizeUnit::BYTES),
+                    TestCase::Duration::QUICK);
         // Test 3: test NewtonStep() against explicit port of Linux implementation
-        AddTestCase(new CoDelQueueDiscNewtonStepTest(), TestCase::QUICK);
+        AddTestCase(new CoDelQueueDiscNewtonStepTest(), TestCase::Duration::QUICK);
         // Test 4: test ControlLaw() against explicit port of Linux implementation
-        AddTestCase(new CoDelQueueDiscControlLawTest(), TestCase::QUICK);
+        AddTestCase(new CoDelQueueDiscControlLawTest(), TestCase::Duration::QUICK);
         // Test 5: enqueue/dequeue with drops according to CoDel algorithm
-        AddTestCase(new CoDelQueueDiscBasicDrop(QueueSizeUnit::PACKETS), TestCase::QUICK);
-        AddTestCase(new CoDelQueueDiscBasicDrop(QueueSizeUnit::BYTES), TestCase::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicDrop(QueueSizeUnit::PACKETS), TestCase::Duration::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicDrop(QueueSizeUnit::BYTES), TestCase::Duration::QUICK);
         // Test 6: enqueue/dequeue with marks according to CoDel algorithm
-        AddTestCase(new CoDelQueueDiscBasicMark(QueueSizeUnit::PACKETS), TestCase::QUICK);
-        AddTestCase(new CoDelQueueDiscBasicMark(QueueSizeUnit::BYTES), TestCase::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicMark(QueueSizeUnit::PACKETS), TestCase::Duration::QUICK);
+        AddTestCase(new CoDelQueueDiscBasicMark(QueueSizeUnit::BYTES), TestCase::Duration::QUICK);
     }
 } g_coDelQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/fifo-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/fifo-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/fifo-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/fifo-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -274,8 +274,8 @@
 {
   public:
     FifoQueueDiscTestSuite()
-        : TestSuite("fifo-queue-disc", UNIT)
+        : TestSuite("fifo-queue-disc", Type::UNIT)
     {
-        AddTestCase(new FifoQueueDiscTestCase(), TestCase::QUICK);
+        AddTestCase(new FifoQueueDiscTestCase(), TestCase::Duration::QUICK);
     }
 } g_fifoQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/pie-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/pie-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/pie-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/pie-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -850,8 +850,8 @@
 {
   public:
     PieQueueDiscTestSuite()
-        : TestSuite("pie-queue-disc", UNIT)
+        : TestSuite("pie-queue-disc", Type::UNIT)
     {
-        AddTestCase(new PieQueueDiscTestCase(), TestCase::QUICK);
+        AddTestCase(new PieQueueDiscTestCase(), TestCase::Duration::QUICK);
     }
 } g_pieQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/prio-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/prio-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/prio-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/prio-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -322,8 +322,8 @@
 {
   public:
     PrioQueueDiscTestSuite()
-        : TestSuite("prio-queue-disc", UNIT)
+        : TestSuite("prio-queue-disc", Type::UNIT)
     {
-        AddTestCase(new PrioQueueDiscTestCase(), TestCase::QUICK);
+        AddTestCase(new PrioQueueDiscTestCase(), TestCase::Duration::QUICK);
     }
 } g_prioQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/queue-disc-traces-test-suite.cc ns-3.42/src/traffic-control/test/queue-disc-traces-test-suite.cc
--- ns-3.41/src/traffic-control/test/queue-disc-traces-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/queue-disc-traces-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -592,8 +592,8 @@
 {
   public:
     QueueDiscTracesTestSuite()
-        : TestSuite("queue-disc-traces", UNIT)
+        : TestSuite("queue-disc-traces", Type::UNIT)
     {
-        AddTestCase(new QueueDiscTracesTestCase(), TestCase::QUICK);
+        AddTestCase(new QueueDiscTracesTestCase(), TestCase::Duration::QUICK);
     }
 } g_queueDiscTracesTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/red-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/red-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/red-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/red-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -622,8 +622,8 @@
 {
   public:
     RedQueueDiscTestSuite()
-        : TestSuite("red-queue-disc", UNIT)
+        : TestSuite("red-queue-disc", Type::UNIT)
     {
-        AddTestCase(new RedQueueDiscTestCase(), TestCase::QUICK);
+        AddTestCase(new RedQueueDiscTestCase(), TestCase::Duration::QUICK);
     }
 } g_redQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/tbf-queue-disc-test-suite.cc ns-3.42/src/traffic-control/test/tbf-queue-disc-test-suite.cc
--- ns-3.41/src/traffic-control/test/tbf-queue-disc-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/tbf-queue-disc-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -546,8 +546,8 @@
 {
   public:
     TbfQueueDiscTestSuite()
-        : TestSuite("tbf-queue-disc", UNIT)
+        : TestSuite("tbf-queue-disc", Type::UNIT)
     {
-        AddTestCase(new TbfQueueDiscTestCase(), TestCase::QUICK);
+        AddTestCase(new TbfQueueDiscTestCase(), TestCase::Duration::QUICK);
     }
 } g_tbfQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/traffic-control/test/tc-flow-control-test-suite.cc ns-3.42/src/traffic-control/test/tc-flow-control-test-suite.cc
--- ns-3.41/src/traffic-control/test/tc-flow-control-test-suite.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/traffic-control/test/tc-flow-control-test-suite.cc	2024-05-29 15:29:47.184073700 -0700
@@ -501,20 +501,30 @@
 {
   public:
     TcFlowControlTestSuite()
-        : TestSuite("tc-flow-control", UNIT)
+        : TestSuite("tc-flow-control", Type::UNIT)
     {
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 10), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 10), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 9, 10), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 10, 10), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 11, 10), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 15, 10), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 1), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 2, 1), TestCase::QUICK);
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 1), TestCase::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 10),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 10),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 9, 10),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 10, 10),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 11, 10),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 15, 10),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 1, 1),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 2, 1),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::PACKETS, 5, 1),
+                    TestCase::Duration::QUICK);
 
         // TODO: Right now, this test only works for 5000B and 10 packets (it's hard coded). Should
         // also be made parametric.
-        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::BYTES, 5000, 10), TestCase::QUICK);
+        AddTestCase(new TcFlowControlTestCase(QueueSizeUnit::BYTES, 5000, 10),
+                    TestCase::Duration::QUICK);
     }
 } g_tcFlowControlTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/examples/uan-6lowpan-example.cc ns-3.42/src/uan/examples/uan-6lowpan-example.cc
--- ns-3.41/src/uan/examples/uan-6lowpan-example.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/uan/examples/uan-6lowpan-example.cc	2024-05-29 15:29:47.184073700 -0700
@@ -30,8 +30,10 @@
 #include "ns3/uan-helper.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 /**
+ * \ingroup uan
  *
  * This example shows the usage of UDP over 6LoWPAN to transfer data.
  * Two nodes are sending their remaining energy percentage (1 byte)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/examples/uan-ipv4-example.cc ns-3.42/src/uan/examples/uan-ipv4-example.cc
--- ns-3.41/src/uan/examples/uan-ipv4-example.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/uan/examples/uan-ipv4-example.cc	2024-05-29 15:29:47.184073700 -0700
@@ -28,8 +28,10 @@
 #include "ns3/uan-helper.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 /**
+ * \ingroup uan
  *
  * This example shows the usage of UDP over IPv4 to transfer data.
  * Two nodes are sending their remaining energy percentage (1 byte)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/examples/uan-ipv6-example.cc ns-3.42/src/uan/examples/uan-ipv6-example.cc
--- ns-3.41/src/uan/examples/uan-ipv6-example.cc	2024-02-09 14:44:08.537794600 -0800
+++ ns-3.42/src/uan/examples/uan-ipv6-example.cc	2024-05-29 15:29:47.184073700 -0700
@@ -28,8 +28,10 @@
 #include "ns3/uan-helper.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 /**
+ * \ingroup uan
  *
  * This example shows the usage of UDP over IPv6 to transfer data.
  * Two nodes are sending their remaining energy percentage (1 byte)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/examples/uan-raw-example.cc ns-3.42/src/uan/examples/uan-raw-example.cc
--- ns-3.41/src/uan/examples/uan-raw-example.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/examples/uan-raw-example.cc	2024-05-29 15:29:47.184073700 -0700
@@ -32,6 +32,7 @@
 using namespace ns3;
 
 /**
+ * \ingroup uan
  *
  * This example shows the usage of raw packets transfer data.
  * Two nodes are sending their remaining energy percentage (1 byte)
@@ -130,11 +131,11 @@
     Ptr<UanChannel> channel = CreateObject<UanChannel>();
     UanHelper uanHelper;
     NetDeviceContainer netDeviceContainer = uanHelper.Install(m_nodes, channel);
-    EnergySourceContainer energySourceContainer;
+    energy::EnergySourceContainer energySourceContainer;
     auto node = m_nodes.Begin();
     while (node != m_nodes.End())
     {
-        energySourceContainer.Add((*node)->GetObject<EnergySourceContainer>()->Get(0));
+        energySourceContainer.Add((*node)->GetObject<energy::EnergySourceContainer>()->Get(0));
         node++;
     }
     AcousticModemEnergyModelHelper acousticModemEnergyModelHelper;
@@ -193,7 +194,8 @@
     while (node != m_nodes.End())
     {
         uint8_t energy =
-            ((*node)->GetObject<EnergySourceContainer>()->Get(0)->GetEnergyFraction()) * 100;
+            ((*node)->GetObject<energy::EnergySourceContainer>()->Get(0)->GetEnergyFraction()) *
+            100;
 
         Ptr<Packet> pkt = Create<Packet>(&energy, 1);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/examples/uan-rc-example.cc ns-3.42/src/uan/examples/uan-rc-example.cc
--- ns-3.41/src/uan/examples/uan-rc-example.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/examples/uan-rc-example.cc	2024-05-29 15:29:47.184073700 -0700
@@ -19,7 +19,8 @@
 
 /**
  * \file uan-rc-example.cc
- * \ingroup UAN
+ * \ingroup uan
+ *
  * This example uses UanMacRc and UanMacRcGw which combined form a system
  * using what is referred to as RC-MAC.  Details of RC-MAC will be published
  * soon.  In brief terms, RC-MAC is a dual channel protocol wherein the
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/helper/acoustic-modem-energy-model-helper.cc ns-3.42/src/uan/helper/acoustic-modem-energy-model-helper.cc
--- ns-3.41/src/uan/helper/acoustic-modem-energy-model-helper.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/helper/acoustic-modem-energy-model-helper.cc	2024-05-29 15:29:47.184073700 -0700
@@ -55,8 +55,9 @@
  * Private function starts here.
  */
 
-Ptr<DeviceEnergyModel>
-AcousticModemEnergyModelHelper::DoInstall(Ptr<NetDevice> device, Ptr<EnergySource> source) const
+Ptr<energy::DeviceEnergyModel>
+AcousticModemEnergyModelHelper::DoInstall(Ptr<NetDevice> device,
+                                          Ptr<energy::EnergySource> source) const
 {
     NS_ASSERT(device);
     NS_ASSERT(source);
@@ -83,8 +84,8 @@
     // set node pointer
     source->SetNode(node);
     // create and install energy model callback
-    DeviceEnergyModel::ChangeStateCallback cb;
-    cb = MakeCallback(&DeviceEnergyModel::ChangeState, model);
+    energy::DeviceEnergyModel::ChangeStateCallback cb;
+    cb = MakeCallback(&energy::DeviceEnergyModel::ChangeState, model);
     uanPhy->SetEnergyModelCallback(cb);
 
     return model;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/helper/acoustic-modem-energy-model-helper.h ns-3.42/src/uan/helper/acoustic-modem-energy-model-helper.h
--- ns-3.41/src/uan/helper/acoustic-modem-energy-model-helper.h	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/helper/acoustic-modem-energy-model-helper.h	2024-05-29 15:29:47.184073700 -0700
@@ -71,8 +71,8 @@
      * \param source Pointer to EnergySource installed on node.
      * \return The energy model.
      */
-    Ptr<DeviceEnergyModel> DoInstall(Ptr<NetDevice> device,
-                                     Ptr<EnergySource> source) const override;
+    Ptr<energy::DeviceEnergyModel> DoInstall(Ptr<NetDevice> device,
+                                             Ptr<energy::EnergySource> source) const override;
 
   private:
     /** Energy model factory. */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/acoustic-modem-energy-model.cc ns-3.42/src/uan/model/acoustic-modem-energy-model.cc
--- ns-3.41/src/uan/model/acoustic-modem-energy-model.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/acoustic-modem-energy-model.cc	2024-05-29 15:29:47.184073700 -0700
@@ -40,7 +40,7 @@
 {
     static TypeId tid =
         TypeId("ns3::AcousticModemEnergyModel")
-            .SetParent<DeviceEnergyModel>()
+            .SetParent<energy::DeviceEnergyModel>()
             .AddConstructor<AcousticModemEnergyModel>()
             .AddAttribute("TxPowerW",
                           "The modem Tx power in Watts",
@@ -103,7 +103,7 @@
 }
 
 void
-AcousticModemEnergyModel::SetEnergySource(Ptr<EnergySource> source)
+AcousticModemEnergyModel::SetEnergySource(Ptr<energy::EnergySource> source)
 {
     NS_LOG_FUNCTION(this << source);
     NS_ASSERT(source);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/acoustic-modem-energy-model.h ns-3.42/src/uan/model/acoustic-modem-energy-model.h
--- ns-3.41/src/uan/model/acoustic-modem-energy-model.h	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/acoustic-modem-energy-model.h	2024-05-29 15:29:47.184073700 -0700
@@ -52,7 +52,7 @@
  *     in In Proc. IEEE OCEANS05 Conf, 2005.
  *     URL: http://ieeexplore.ieee.org/iel5/10918/34367/01639901.pdf
  */
-class AcousticModemEnergyModel : public DeviceEnergyModel
+class AcousticModemEnergyModel : public energy::DeviceEnergyModel
 {
   public:
     /** Callback type for energy depletion handling. */
@@ -87,7 +87,7 @@
     virtual Ptr<Node> GetNode() const;
 
     // Inherited methods.
-    void SetEnergySource(Ptr<EnergySource> source) override;
+    void SetEnergySource(Ptr<energy::EnergySource> source) override;
     double GetTotalEnergyConsumption() const override;
 
     /**
@@ -216,8 +216,8 @@
     void SetMicroModemState(const int state);
 
   private:
-    Ptr<Node> m_node;           //!< The node hosting this transducer.
-    Ptr<EnergySource> m_source; //!< The energy source.
+    Ptr<Node> m_node;                   //!< The node hosting this transducer.
+    Ptr<energy::EnergySource> m_source; //!< The energy source.
 
     // Member variables for power consumption in different modem states.
     double m_txPowerW;    //!< The transmitter power, in watts.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-header-common.cc ns-3.42/src/uan/model/uan-header-common.cc
--- ns-3.41/src/uan/model/uan-header-common.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-header-common.cc	2024-05-29 15:29:47.184073700 -0700
@@ -24,6 +24,7 @@
 static const uint16_t ARP_PROT_NUMBER = 0x0806;
 static const uint16_t IPV4_PROT_NUMBER = 0x0800;
 static const uint16_t IPV6_PROT_NUMBER = 0x86DD;
+static const uint16_t SIXLOWPAN_PROT_NUMBER = 0xA0ED;
 
 namespace ns3
 {
@@ -103,6 +104,10 @@
     {
         m_uanProtocolBits.m_protocolNumber = 3;
     }
+    else if (protocolNumber == SIXLOWPAN_PROT_NUMBER)
+    {
+        m_uanProtocolBits.m_protocolNumber = 4;
+    }
     else
     {
         NS_ASSERT_MSG(false, "UanHeaderCommon::SetProtocolNumber(): Protocol not supported");
@@ -142,6 +147,10 @@
     {
         return IPV6_PROT_NUMBER;
     }
+    if (m_uanProtocolBits.m_protocolNumber == 4)
+    {
+        return SIXLOWPAN_PROT_NUMBER;
+    }
     return 0;
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-header-common.h ns-3.42/src/uan/model/uan-header-common.h
--- ns-3.41/src/uan/model/uan-header-common.h	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-header-common.h	2024-05-29 15:29:47.184073700 -0700
@@ -58,6 +58,7 @@
  * prtcl=1 (IPv4)
  * prtcl=2 (ARP)
  * prtcl=3 (IPv6)
+ * prtcl=4 (6LoWPAN)
  *
  * type: The type field is MAC protocol specific
  */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-mac-rc.cc ns-3.42/src/uan/model/uan-mac-rc.cc
--- ns-3.41/src/uan/model/uan-mac-rc.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-mac-rc.cc	2024-05-29 15:29:47.184073700 -0700
@@ -294,7 +294,7 @@
         Associate();
         return true;
     case IDLE:
-        if (!m_rtsEvent.IsRunning())
+        if (!m_rtsEvent.IsPending())
         {
             SendRts();
         }
@@ -489,7 +489,7 @@
     m_state = IDLE;
     if (!m_pktQueue.empty())
     {
-        if (m_rtsEvent.IsRunning())
+        if (m_rtsEvent.IsPending())
         {
             m_rtsEvent.Cancel();
         }
@@ -625,7 +625,7 @@
         SendPacket(pkt, m_currentRate + m_numRates);
     }
     m_state = GWPSENT;
-    NS_ASSERT(!m_rtsEvent.IsRunning());
+    NS_ASSERT(!m_rtsEvent.IsPending());
     m_ev->SetAttribute("Mean", DoubleValue(1 / m_retryRate));
     double timeout = m_ev->GetValue();
     m_rtsEvent = Simulator::Schedule(Seconds(timeout), &UanMacRc::AssociateTimeout, this);
@@ -659,7 +659,7 @@
         SendPacket(pkt, m_currentRate + m_numRates);
         m_resList.push_back(res);
     }
-    NS_ASSERT(!m_rtsEvent.IsRunning());
+    NS_ASSERT(!m_rtsEvent.IsPending());
     m_ev->SetAttribute("Mean", DoubleValue(1 / m_retryRate));
     double timeout = m_ev->GetValue();
     m_rtsEvent = Simulator::Schedule(Seconds(timeout), &UanMacRc::AssociateTimeout, this);
@@ -693,7 +693,7 @@
         SendPacket(pkt, m_currentRate + m_numRates);
     }
     m_state = RTSSENT;
-    NS_ASSERT(!m_rtsEvent.IsRunning());
+    NS_ASSERT(!m_rtsEvent.IsPending());
     m_ev->SetAttribute("Mean", DoubleValue(1 / m_retryRate));
     double timeout = m_ev->GetValue();
     m_rtsEvent = Simulator::Schedule(Seconds(timeout), &UanMacRc::RtsTimeout, this);
@@ -711,11 +711,8 @@
         Ptr<Packet> pkt = phyDual->GetPhy1PacketRx();
         UanHeaderCommon ch;
         pkt->PeekHeader(ch);
-        if (ch.GetType() == TYPE_CTS || ch.GetType() == TYPE_ACK)
-        {
-            phy1ok = false;
-        }
-        else if (ch.GetDest() == Mac8Address::ConvertFrom(GetAddress()))
+        if (ch.GetType() == TYPE_CTS || ch.GetType() == TYPE_ACK ||
+            ch.GetDest() == Mac8Address::ConvertFrom(GetAddress()))
         {
             phy1ok = false;
         }
@@ -758,7 +755,7 @@
         SendPacket(pkt, m_currentRate + m_numRates);
     }
     m_state = RTSSENT;
-    NS_ASSERT(!m_rtsEvent.IsRunning());
+    NS_ASSERT(!m_rtsEvent.IsPending());
     m_ev->SetAttribute("Mean", DoubleValue(1 / m_retryRate));
     double timeout = m_ev->GetValue();
     m_rtsEvent = Simulator::Schedule(Seconds(timeout), &UanMacRc::RtsTimeout, this);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-phy-dual.cc ns-3.42/src/uan/model/uan-phy-dual.cc
--- ns-3.41/src/uan/model/uan-phy-dual.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-phy-dual.cc	2024-05-29 15:29:47.184073700 -0700
@@ -251,7 +251,7 @@
 }
 
 void
-UanPhyDual::SetEnergyModelCallback(DeviceEnergyModel::ChangeStateCallback callback)
+UanPhyDual::SetEnergyModelCallback(energy::DeviceEnergyModel::ChangeStateCallback callback)
 {
     NS_LOG_DEBUG("Not Implemented");
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-phy-dual.h ns-3.42/src/uan/model/uan-phy-dual.h
--- ns-3.41/src/uan/model/uan-phy-dual.h	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-phy-dual.h	2024-05-29 15:29:47.184073700 -0700
@@ -90,7 +90,7 @@
     static TypeId GetTypeId();
 
     // Inherited methods:
-    void SetEnergyModelCallback(DeviceEnergyModel::ChangeStateCallback callback) override;
+    void SetEnergyModelCallback(energy::DeviceEnergyModel::ChangeStateCallback callback) override;
     void EnergyDepletionHandler() override;
     void EnergyRechargeHandler() override;
     void SendPacket(Ptr<Packet> pkt, uint32_t modeNum) override;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-phy-gen.cc ns-3.42/src/uan/model/uan-phy-gen.cc
--- ns-3.41/src/uan/model/uan-phy-gen.cc	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-phy-gen.cc	2024-05-29 15:29:47.184073700 -0700
@@ -631,7 +631,7 @@
 }
 
 void
-UanPhyGen::SetEnergyModelCallback(DeviceEnergyModel::ChangeStateCallback cb)
+UanPhyGen::SetEnergyModelCallback(energy::DeviceEnergyModel::ChangeStateCallback cb)
 {
     NS_LOG_FUNCTION(this);
     m_energyCallback = cb;
@@ -656,13 +656,13 @@
                                             << ", stopping rx/tx activities");
 
     m_state = DISABLED;
-    if (m_txEndEvent.IsRunning())
+    if (m_txEndEvent.IsPending())
     {
         Simulator::Cancel(m_txEndEvent);
         NotifyTxDrop(m_pktTx);
         m_pktTx = nullptr;
     }
-    if (m_rxEndEvent.IsRunning())
+    if (m_rxEndEvent.IsPending())
     {
         Simulator::Cancel(m_rxEndEvent);
         NotifyRxDrop(m_pktRx);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-phy-gen.h ns-3.42/src/uan/model/uan-phy-gen.h
--- ns-3.41/src/uan/model/uan-phy-gen.h	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-phy-gen.h	2024-05-29 15:29:47.184073700 -0700
@@ -278,7 +278,7 @@
     static TypeId GetTypeId();
 
     // Inherited methods
-    void SetEnergyModelCallback(DeviceEnergyModel::ChangeStateCallback cb) override;
+    void SetEnergyModelCallback(energy::DeviceEnergyModel::ChangeStateCallback cb) override;
     void EnergyDepletionHandler() override;
     void EnergyRechargeHandler() override;
     void SendPacket(Ptr<Packet> pkt, uint32_t modeNum) override;
@@ -352,7 +352,7 @@
     Ptr<UniformRandomVariable> m_pg;
 
     /** Energy model callback. */
-    DeviceEnergyModel::ChangeStateCallback m_energyCallback;
+    energy::DeviceEnergyModel::ChangeStateCallback m_energyCallback;
     /** A packet destined for this Phy was received without error. */
     ns3::TracedCallback<Ptr<const Packet>, double, UanTxMode> m_rxOkLogger;
     /** A packet destined for this Phy was received with error. */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/model/uan-phy.h ns-3.42/src/uan/model/uan-phy.h
--- ns-3.41/src/uan/model/uan-phy.h	2024-02-09 14:44:08.557794800 -0800
+++ ns-3.42/src/uan/model/uan-phy.h	2024-05-29 15:29:47.184073700 -0700
@@ -219,7 +219,8 @@
      *
      * \param callback The DeviceEnergyModel change state callback.
      */
-    virtual void SetEnergyModelCallback(DeviceEnergyModel::ChangeStateCallback callback) = 0;
+    virtual void SetEnergyModelCallback(
+        energy::DeviceEnergyModel::ChangeStateCallback callback) = 0;
     /**
      * Handle the energy depletion event.
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/test/uan-energy-model-test.cc ns-3.42/src/uan/test/uan-energy-model-test.cc
--- ns-3.41/src/uan/test/uan-energy-model-test.cc	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/uan/test/uan-energy-model-test.cc	2024-05-29 15:29:47.188073900 -0700
@@ -36,6 +36,7 @@
 #include "ns3/uan-prop-model-ideal.h"
 
 using namespace ns3;
+using namespace ns3::energy;
 
 NS_LOG_COMPONENT_DEFINE("UanEnergyModelTestSuite");
 
@@ -334,10 +335,10 @@
 };
 
 UanEnergyModelTestSuite::UanEnergyModelTestSuite()
-    : TestSuite("uan-energy-model", UNIT)
+    : TestSuite("uan-energy-model", Type::UNIT)
 {
-    AddTestCase(new AcousticModemEnergyTestCase, TestCase::QUICK);
-    AddTestCase(new AcousticModemEnergyDepletionTestCase, TestCase::QUICK);
+    AddTestCase(new AcousticModemEnergyTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new AcousticModemEnergyDepletionTestCase, TestCase::Duration::QUICK);
 }
 
 // create an instance of the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/uan/test/uan-test.cc ns-3.42/src/uan/test/uan-test.cc
--- ns-3.41/src/uan/test/uan-test.cc	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/uan/test/uan-test.cc	2024-05-29 15:29:47.188073900 -0700
@@ -323,9 +323,9 @@
 };
 
 UanTestSuite::UanTestSuite()
-    : TestSuite("devices-uan", UNIT)
+    : TestSuite("devices-uan", Type::UNIT)
 {
-    AddTestCase(new UanTest, TestCase::QUICK);
+    AddTestCase(new UanTest, TestCase::Duration::QUICK);
 }
 
 static UanTestSuite g_uanTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/virtual-net-device/model/virtual-net-device.cc ns-3.42/src/virtual-net-device/model/virtual-net-device.cc
--- ns-3.41/src/virtual-net-device/model/virtual-net-device.cc	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/virtual-net-device/model/virtual-net-device.cc	2024-05-29 15:29:47.188073900 -0700
@@ -224,7 +224,7 @@
 Address
 VirtualNetDevice::GetBroadcast() const
 {
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
@@ -236,13 +236,13 @@
 Address
 VirtualNetDevice::GetMulticast(Ipv4Address multicastGroup) const
 {
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 Address
 VirtualNetDevice::GetMulticast(Ipv6Address addr) const
 {
-    return Mac48Address("ff:ff:ff:ff:ff:ff");
+    return Mac48Address::GetBroadcast();
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/model/pyviz.cc ns-3.42/src/visualizer/model/pyviz.cc
--- ns-3.41/src/visualizer/model/pyviz.cc	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/model/pyviz.cc	2024-05-29 15:29:47.188073900 -0700
@@ -601,21 +601,13 @@
     WifiMacHeader hdr;
     NS_ABORT_IF(packet->PeekHeader(hdr) == 0);
     Mac48Address destinationAddress;
-    if (hdr.IsToDs() && !hdr.IsFromDs())
+    if (hdr.IsToDs())
     {
         destinationAddress = hdr.GetAddr3();
     }
-    else if (!hdr.IsToDs() && hdr.IsFromDs())
-    {
-        destinationAddress = hdr.GetAddr1();
-    }
-    else if (!hdr.IsToDs() && !hdr.IsFromDs())
-    {
-        destinationAddress = hdr.GetAddr1();
-    }
     else
     {
-        destinationAddress = hdr.GetAddr3();
+        destinationAddress = hdr.GetAddr1();
     }
     TraceNetDevTxCommon(context, packet, destinationAddress);
 }
@@ -769,19 +761,15 @@
     WifiMacHeader hdr;
     NS_ABORT_IF(packet->PeekHeader(hdr) == 0);
     Mac48Address sourceAddress;
-    if (hdr.IsToDs() && !hdr.IsFromDs())
+    if (!hdr.IsFromDs())
     {
         sourceAddress = hdr.GetAddr2();
     }
-    else if (!hdr.IsToDs() && hdr.IsFromDs())
+    else if (!hdr.IsToDs())
     {
         sourceAddress = hdr.GetAddr3();
     }
-    else if (!hdr.IsToDs() && !hdr.IsFromDs())
-    {
-        sourceAddress = hdr.GetAddr2();
-    }
-    else
+    else // if (hdr.IsToDs())
     {
         sourceAddress = hdr.GetAddr4();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/visualizer/core.py ns-3.42/src/visualizer/visualizer/core.py
--- ns-3.41/src/visualizer/visualizer/core.py	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/visualizer/core.py	2024-05-29 15:29:47.188073900 -0700
@@ -253,8 +253,8 @@
         self.visualizer.simulation.lock.acquire()
         try:
             ns3_node = ns.NodeList.GetNode(self.node_index)
-            ipv4 = ns.cppyy.gbl.getNodeIpv4(ns3_node)
-            ipv6 = ns.cppyy.gbl.getNodeIpv6(ns3_node)
+            ipv4 = ns3_node.GetObject[ns.Ipv4]().__deref__()
+            ipv6 = ns3_node.GetObject[ns.Ipv6]().__deref__()
 
             name = "<b><u>Node %i</u></b>" % self.node_index
             node_name = ns.Names.FindName(ns3_node)
@@ -266,12 +266,10 @@
 
             self.emit("query-extra-tooltip-info", lines)
 
-            mob = ns.cppyy.gbl.hasMobilityModel(ns3_node)
+            mob = ns3_node.GetObject[ns.MobilityModel]()
             if mob:
-                mobility_model_name = ns.cppyy.gbl.getMobilityModelName(ns3_node)
-                lines.append(
-                    "  <b>Mobility Model</b>: %s" % ns.cppyy.gbl.getMobilityModelName(ns3_node)
-                )
+                mobility_model_name = mob.__deref__().GetInstanceTypeId().GetName()
+                lines.append("  <b>Mobility Model</b>: %s" % mobility_model_name)
 
             for devI in range(ns3_node.GetNDevices()):
                 lines.append("")
@@ -554,7 +552,7 @@
         """
         if self._has_mobility is None:
             node = ns.NodeList.GetNode(self.node_index)
-            self._has_mobility = ns.cppyy.gbl.hasMobilityModel(node)
+            self._has_mobility = node.GetObject[ns.MobilityModel]()
         return self._has_mobility
 
 
@@ -1214,10 +1212,10 @@
             node_name = "Node %i" % nodeI
             node_view = self.get_node(nodeI)
 
-            mobility = ns.cppyy.gbl.hasMobilityModel(node)
+            mobility = node.GetObject[ns.MobilityModel]()
             if mobility:
                 node_view.set_color("red")
-                pos = ns.cppyy.gbl.getNodePosition(node)
+                pos = node.GetObject[ns.MobilityModel]().__deref__().GetPosition()
                 node_view.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y))
                 # print "node has mobility position -> ", "%f,%f" % (pos.x, pos.y)
             else:
@@ -1323,9 +1321,9 @@
         for node in self.nodes.values():
             if node.has_mobility:
                 ns3_node = ns.NodeList.GetNode(node.node_index)
-                mobility = ns.cppyy.gbl.hasMobilityModel(ns3_node)
+                mobility = ns3_node.GetObject[ns.MobilityModel]()
                 if mobility:
-                    pos = ns.cppyy.gbl.getNodePosition(ns3_node)
+                    pos = ns3_node.GetObject[ns.MobilityModel]().__deref__().GetPosition()
                     x, y = transform_point_simulation_to_canvas(pos.x, pos.y)
                     node.set_position(x, y)
                     if node is self.follow_node:
@@ -1724,12 +1722,12 @@
         self.simulation.lock.acquire()
         try:
             ns3_node = ns.NodeList.GetNode(node.node_index)
-            mob = ns.cppyy.gbl.hasMobilityModel(ns3_node)
+            mob = ns3_node.GetObject[ns.MobilityModel]()
             if not mob:
                 return
             if self.node_drag_state is not None:
                 return
-            pos = ns.cppyy.gbl.getNodePosition(ns3_node)
+            pos = ns3_node.GetObject[ns.MobilityModel]().__deref__().GetPosition()
         finally:
             self.simulation.lock.release()
         devpos = self.canvas.get_window().get_device_position(event.device)
@@ -1743,7 +1741,7 @@
         self.simulation.lock.acquire()
         try:
             ns3_node = ns.NodeList.GetNode(node.node_index)
-            mob = ns.cppyy.gbl.hasMobilityModel(ns3_node)
+            mob = ns3_node.GetObject[ns.MobilityModel]()
             if not mob:
                 return False
             if self.node_drag_state is None:
@@ -1984,7 +1982,14 @@
     add_initialization_hook(hook)
 
 
+_run_once = False
+
+
 def start():
+    global _run_once
+    if _run_once:
+        return
+    _run_once = True
     assert Visualizer.INSTANCE is None
     if _import_error is not None:
         import sys
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/visualizer/__init__.py ns-3.42/src/visualizer/visualizer/__init__.py
--- ns-3.41/src/visualizer/visualizer/__init__.py	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/visualizer/__init__.py	2024-05-29 15:29:47.188073900 -0700
@@ -1,28 +1,3 @@
 from ns import *
 
-# Some useful tricks for visualizer
-# we need to check if the node has a mobility model, but we can't pass Ptr<MobilityModel> to python
-ns.cppyy.cppdef(
-    """using namespace ns3; bool hasMobilityModel(Ptr<Node> node){ return !(node->GetObject<MobilityModel>() == 0); };"""
-)
-ns.cppyy.cppdef(
-    """using namespace ns3; Vector3D getNodePosition(Ptr<Node> node){ return node->GetObject<MobilityModel>()->GetPosition(); };"""
-)
-ns.cppyy.cppdef(
-    """using namespace ns3; Ptr<Ipv4> getNodeIpv4(Ptr<Node> node){ return node->GetObject<Ipv4>(); };"""
-)
-ns.cppyy.cppdef(
-    """using namespace ns3; Ptr<Ipv6> getNodeIpv6(Ptr<Node> node){ return node->GetObject<Ipv6>(); };"""
-)
-ns.cppyy.cppdef(
-    """using namespace ns3; std::string getMobilityModelName(Ptr<Node> node){ return node->GetObject<MobilityModel>()->GetInstanceTypeId().GetName(); };"""
-)
-ns.cppyy.cppdef(
-    """using namespace ns3; bool hasOlsr(Ptr<Node> node){ return !(node->GetObject<olsr::RoutingProtocol>() == 0); };"""
-)
-ns.cppyy.cppdef(
-    """using namespace ns3; Ptr<olsr::RoutingProtocol> getNodeOlsr(Ptr<Node> node){ return node->GetObject<olsr::RoutingProtocol>(); };"""
-)
-
-
 from .core import add_initialization_hook, register_plugin, set_bounds, start
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/visualizer/plugins/ipv4_routing_table.py ns-3.42/src/visualizer/visualizer/plugins/ipv4_routing_table.py
--- ns-3.41/src/visualizer/visualizer/plugins/ipv4_routing_table.py	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/visualizer/plugins/ipv4_routing_table.py	2024-05-29 15:29:47.188073900 -0700
@@ -110,7 +110,7 @@
         @return none
         """
         node = ns.NodeList.GetNode(self.node_index)
-        ipv4 = ns.cppyy.gbl.getNodeIpv4(node)
+        ipv4 = node.GetObject[ns.Ipv4]().__deref__()
         routing = ipv4.GetRoutingProtocol()
         if routing is None:
             return
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/visualizer/plugins/olsr.py ns-3.42/src/visualizer/visualizer/plugins/olsr.py
--- ns-3.41/src/visualizer/visualizer/plugins/olsr.py	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/visualizer/plugins/olsr.py	2024-05-29 15:29:47.188073900 -0700
@@ -104,12 +104,12 @@
         """
         node = ns.NodeList.GetNode(self.node_index)
         ipv4 = node.GetObject(ns.Ipv4.GetTypeId())
-        if not ns.cppyy.gbl.hasOlsr(ns3_node):
+        olsr = ns3_node.GetObject[ns.olsr.RoutingProtocol]()
+        if not olsr:
             return
-        olsr = ns.cppyy.gbl.getNodeOlsr(node)
 
         self.table_model.clear()
-        for route in olsr.GetRoutingTableEntries():
+        for route in olsr.__deref__().GetRoutingTableEntries():
             tree_iter = self.table_model.append()
             netdevice = ipv4.GetNetDevice(route.interface)
             if netdevice is None:
@@ -133,7 +133,7 @@
 
 def populate_node_menu(viz, node, menu):
     ns3_node = ns.NodeList.GetNode(node.node_index)
-    if not ns.cppyy.gbl.hasOlsr(ns3_node):
+    if not ns3_node.GetObject[ns.olsr.RoutingProtocol]():
         print("No OLSR")
         return
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/visualizer/plugins/show_last_packets.py ns-3.42/src/visualizer/visualizer/plugins/show_last_packets.py
--- ns-3.41/src/visualizer/visualizer/plugins/show_last_packets.py	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/visualizer/plugins/show_last_packets.py	2024-05-29 15:29:47.188073900 -0700
@@ -106,7 +106,7 @@
                 if sample.device is None:
                     interface_name = "(unknown)"
                 else:
-                    interface_name = ns.core.Names.FindName(sample.device)
+                    interface_name = ns.Names.FindName(sample.device)
                     if not interface_name:
                         interface_name = "(interface %i)" % sample.device.GetIfIndex()
                 self.table_model.set(
@@ -138,7 +138,7 @@
         self.win.set_title("Last packets for node %i" % node_index)
         self.visualizer = visualizer
         self.viz_node = visualizer.get_node(node_index)
-        self.node = ns.network.NodeList.GetNode(node_index)
+        self.node = ns.NodeList.GetNode(node_index)
 
         def smart_expand(expander, vbox):
             if expander.get_expanded():
@@ -184,7 +184,7 @@
         # Packet Filter
 
         # - options
-        self.packet_capture_options = ns.visualizer.PyViz.PacketCaptureOptions()
+        self.packet_capture_options = ns.PyViz.PacketCaptureOptions()
         self.packet_capture_options.numLastPackets = 100
 
         packet_filter_vbox = Gtk.VBox(False, 4)
@@ -214,10 +214,10 @@
 
         self.packet_filter_list = []  # list of TypeIdConfig instances
 
-        Header = ns.core.TypeId.LookupByName("ns3::Header")
-        Trailer = ns.core.TypeId.LookupByName("ns3::Trailer")
-        for typeid_i in range(ns.core.TypeId.GetRegisteredN()):
-            typeid = ns.core.TypeId.GetRegistered(typeid_i)
+        Header = ns.TypeId.LookupByName("ns3::Header")
+        Trailer = ns.TypeId.LookupByName("ns3::Trailer")
+        for typeid_i in range(ns.TypeId.GetRegisteredN()):
+            typeid = ns.TypeId.GetRegistered(typeid_i)
             # check if this is a header or trailer subtype
             typeid_tmp = typeid
             type_is_good = False
@@ -242,13 +242,9 @@
 
         def update_capture_options():
             if self.op_AND_button.props.active:
-                self.packet_capture_options.mode = (
-                    ns.visualizer.PyViz.PACKET_CAPTURE_FILTER_HEADERS_AND
-                )
+                self.packet_capture_options.mode = ns.PyViz.PACKET_CAPTURE_FILTER_HEADERS_AND
             else:
-                self.packet_capture_options.mode = (
-                    ns.visualizer.PyViz.PACKET_CAPTURE_FILTER_HEADERS_OR
-                )
+                self.packet_capture_options.mode = ns.PyViz.PACKET_CAPTURE_FILTER_HEADERS_OR
             self.packet_capture_options.numLastPackets = 100
             self.packet_capture_options.headers = [
                 c.typeid for c in self.packet_filter_list if c.selected
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py ns-3.42/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py
--- ns-3.41/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py	2024-05-29 15:29:47.188073900 -0700
@@ -151,17 +151,17 @@
         self.stations = []
 
         for node in viz.nodes.values():
-            ns3_node = ns.network.NodeList.GetNode(node.node_index)
+            ns3_node = ns.NodeList.GetNode(node.node_index)
             for devI in range(ns3_node.GetNDevices()):
                 dev = ns3_node.GetDevice(devI)
-                if not isinstance(dev, ns.wifi.WifiNetDevice):
+                if not isinstance(dev, ns.WifiNetDevice):
                     continue
                 wifi_mac = dev.GetMac()
-                if isinstance(wifi_mac, ns.wifi.StaWifiMac):
+                if isinstance(wifi_mac, ns.StaWifiMac):
                     wifi_link = WifiLink(viz.links_group, node, dev)
                     self.stations.append((dev, node, wifi_link))
-                elif isinstance(wifi_mac, ns.wifi.ApWifiMac):
-                    bssid = ns.network.Mac48Address.ConvertFrom(dev.GetAddress())
+                elif isinstance(wifi_mac, ns.ApWifiMac):
+                    bssid = ns.Mac48Address.ConvertFrom(dev.GetAddress())
                     self.access_points[str(bssid)] = node
         # print "APs: ", self.access_points
         # print "STAs: ", self.stations
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/CMakeLists.txt ns-3.42/src/wifi/CMakeLists.txt
--- ns-3.41/src/wifi/CMakeLists.txt	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/wifi/CMakeLists.txt	2024-05-29 15:29:47.188073900 -0700
@@ -12,6 +12,7 @@
     helper/wifi-mac-helper.cc
     helper/wifi-radio-energy-model-helper.cc
     helper/yans-wifi-helper.cc
+    helper/wifi-phy-rx-trace-helper.cc
     model/addba-extension.cc
     model/adhoc-wifi-mac.cc
     model/ampdu-subframe-header.cc
@@ -42,6 +43,7 @@
     model/frame-capture-model.cc
     model/frame-exchange-manager.cc
     model/he/constant-obss-pd-algorithm.cc
+    model/he/he-6ghz-band-capabilities.cc
     model/he/he-capabilities.cc
     model/he/he-configuration.cc
     model/he/he-frame-exchange-manager.cc
@@ -101,6 +103,7 @@
     model/rate-control/thompson-sampling-wifi-manager.cc
     model/recipient-block-ack-agreement.cc
     model/reduced-neighbor-report.cc
+    model/reference/error-rate-tables.cc
     model/simple-frame-capture-model.cc
     model/snr-tag.cc
     model/spectrum-wifi-phy.cc
@@ -110,6 +113,7 @@
     model/supported-rates.cc
     model/table-based-error-rate-model.cc
     model/threshold-preamble-detection-model.cc
+    model/tim.cc
     model/txop.cc
     model/vht/vht-capabilities.cc
     model/vht/vht-configuration.cc
@@ -148,6 +152,7 @@
     model/wifi-remote-station-manager.cc
     model/wifi-spectrum-phy-interface.cc
     model/wifi-spectrum-signal-parameters.cc
+    model/wifi-standards.cc
     model/wifi-tx-current-model.cc
     model/wifi-tx-parameters.cc
     model/wifi-tx-timer.cc
@@ -156,6 +161,7 @@
     model/yans-error-rate-model.cc
     model/yans-wifi-channel.cc
     model/yans-wifi-phy.cc
+    model/wifi-spectrum-value-helper.cc
 )
 
 set(header_files
@@ -165,6 +171,7 @@
     helper/wifi-mac-helper.h
     helper/wifi-radio-energy-model-helper.h
     helper/yans-wifi-helper.h
+    helper/wifi-phy-rx-trace-helper.h
     model/addba-extension.h
     model/adhoc-wifi-mac.h
     model/ampdu-subframe-header.h
@@ -195,6 +202,7 @@
     model/frame-capture-model.h
     model/frame-exchange-manager.h
     model/he/constant-obss-pd-algorithm.h
+    model/he/he-6ghz-band-capabilities.h
     model/he/he-capabilities.h
     model/he/he-configuration.h
     model/he/he-frame-exchange-manager.h
@@ -264,6 +272,7 @@
     model/supported-rates.h
     model/table-based-error-rate-model.h
     model/threshold-preamble-detection-model.h
+    model/tim.h
     model/txop.h
     model/vht/vht-capabilities.h
     model/vht/vht-configuration.h
@@ -292,6 +301,7 @@
     model/wifi-mpdu-type.h
     model/wifi-mpdu.h
     model/wifi-net-device.h
+    model/wifi-opt-field.h
     model/wifi-phy-band.h
     model/wifi-phy-common.h
     model/wifi-phy-listener.h
@@ -317,6 +327,7 @@
     model/yans-error-rate-model.h
     model/yans-wifi-channel.h
     model/yans-wifi-phy.h
+    model/wifi-spectrum-value-helper.h
 )
 
 build_lib(
@@ -332,6 +343,7 @@
     test/channel-access-manager-test.cc
     test/inter-bss-test-suite.cc
     test/power-rate-adaptation-test.cc
+    test/power-save-test.cc
     test/spectrum-wifi-phy-test.cc
     test/tx-duration-test.cc
     test/wifi-aggregation-test.cc
@@ -339,12 +351,15 @@
     test/wifi-eht-info-elems-test.cc
     test/wifi-emlsr-test.cc
     test/wifi-error-rate-models-test.cc
+    test/wifi-fils-frame-test.cc
+    test/wifi-he-info-elems-test.cc
     test/wifi-ie-fragment-test.cc
     test/wifi-mac-ofdma-test.cc
     test/wifi-mac-queue-test.cc
     test/wifi-mlo-test.cc
     test/wifi-phy-ofdma-test.cc
     test/wifi-phy-reception-test.cc
+    test/wifi-phy-rx-trace-helper-test.cc
     test/wifi-phy-thresholds-test.cc
     test/wifi-primary-channels-test.cc
     test/wifi-ru-allocation-test.cc
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/doc/Makefile ns-3.42/src/wifi/doc/Makefile
--- ns-3.41/src/wifi/doc/Makefile	2024-02-09 14:44:08.561794800 -0800
+++ ns-3.42/src/wifi/doc/Makefile	2024-05-29 15:29:47.188073900 -0700
@@ -13,7 +13,8 @@
 	$(FIGURES)/WifiArchitecture.dia \
 	$(FIGURES)/PhyEntityHierarchy.dia \
 	$(FIGURES)/WifiPpduHierarchy.dia \
-	$(FIGURES)/FemHierarchy.dia
+	$(FIGURES)/FemHierarchy.dia \
+	$(FIGURES)/wifi-phy-rx-trace-helper.dia
 
 # specify eps figures from which .png and .pdf figures need to be built
 
@@ -23,6 +24,7 @@
 	$(FIGURES)/PhyEntityHierarchy.eps \
 	$(FIGURES)/WifiPpduHierarchy.eps \
 	$(FIGURES)/FemHierarchy.eps \
+	$(FIGURES)/wifi-phy-rx-trace-helper.eps \
         $(FIGURES)/assoc-manager.eps \
         $(FIGURES)/clear-channel.eps \
         $(FIGURES)/emlsr-dl-txop.eps \
@@ -63,7 +65,7 @@
 
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -W --keep-going
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = build
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/doc/source/wifi-design.rst ns-3.42/src/wifi/doc/source/wifi-design.rst
--- ns-3.41/src/wifi/doc/source/wifi-design.rst	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/doc/source/wifi-design.rst	2024-05-29 15:29:47.192073800 -0700
@@ -686,7 +686,11 @@
 First, the physical layer must send signals compatible with the
 Spectrum channel framework, and in particular, the
 ``MultiModelSpectrumChannel`` that allows signals from different
-technologies to coexist.  Second, the InterferenceHelper must be
+technologies to coexist (``SingleModelSpectrumChannel`` may also work
+for pure Wi-Fi simulations in 5 GHz and 6 GHz bands (but not 2.4 GHz);
+if you get an error using ``SingleModelSpectrumChannel``, switch to
+``MultiModelSpectrumChannel``).
+Second, the InterferenceHelper must be
 extended to support the insertion of non-Wi-Fi signals and to
 add their received power to the noise, in the same way that
 unintended Wi-Fi signals (perhaps from a different SSID or arriving
@@ -944,6 +948,14 @@
 For example, if a STA is operating on a 40 MHz channel and the secondary20 channel
 is indicated to be busy, transmissions will occur on the primary20 channel.
 
+In |ns3|, by default, beacons for both QoS and non-QoS APs access the channel after a PIFS interval (SIFS
+plus one slot time), and with zero backoff (CWmin and CWmax both set to zero), giving
+them higher priority than other access categories.  Beacons are given a
+separate Txop from data frames.  The DCF parameters described above are non-standard,
+but appear to be what some vendors have implemented in their products.  To change the
+DCF parameters for |ns3| access points, the ``ApWifiMac::DoCompleteConfig()`` method
+must be manually edited.
+
 The higher-level MAC functions are implemented in a set of other C++ classes and
 deal with:
 
@@ -1516,7 +1528,7 @@
   ``frame-exchange-manager.*`` or its subclasses to accomplish this.
   Handling of control frames is performed in ``FrameExchangeManager::ReceiveMpdu``.
 * MAC high modification. For example, handling new management frames (think beacon/probe),
-  beacon/probe generation.  Users usually make changes to ``wifi-mac.*``,``sta-wifi-mac.*``, ``ap-wifi-mac.*``, or ``adhoc-wifi-mac.*`` to accomplish this.
+  beacon/probe generation.  Users usually make changes to ``wifi-mac.*``, ``sta-wifi-mac.*``, ``ap-wifi-mac.*``, or ``adhoc-wifi-mac.*`` to accomplish this.
 * Wi-Fi queue management.  The files ``txop.*`` and ``qos-txop.*`` are of interest for this task.
 * Channel access management.  Users should modify the files ``channel-access-manager.*``, which grant access to
   ``Txop`` and ``QosTxop``.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/doc/source/wifi-user.rst ns-3.42/src/wifi/doc/source/wifi-user.rst
--- ns-3.41/src/wifi/doc/source/wifi-user.rst	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/doc/source/wifi-user.rst	2024-05-29 15:29:47.196073800 -0700
@@ -804,6 +804,240 @@
 deviate from the default behavior; the example scripts show how to do some of
 this reconfiguration.
 
+WifiPhyRxTraceHelper
+====================
+The ``WifiPhyRxTraceHelper`` can be used to collect statistics and records of Wi-Fi
+reception events at the physical layer, such as whether a PPDU was received or was dropped for
+some reason, and whether a PPDU overlapped in time (collided) with one or more other PPDUs on the
+channel.  Two possible types of studies that may be helped by this feature are:
+
+1) Wi-Fi PPDU and MPDU reception outcomes to assess the performance of spatial reuse mechanisms
+
+2) Calculation of airtime fairness between contending stations on a network
+
+The trace helper works by hooking PHY-level traces on the applicable nodes, devices, and
+links and maintaining per-receiver records of all of the Wi-Fi PPDUs that are received,
+from each receiver's vantage point.  These records include a listing of all other PPDUs
+that may have overlapped in time and/or frequency for a given PPDU, and the received
+signal power of each PPDU involved, and the outcome of the attempt at reception (whether
+the PPDU was dropped entirely, or whether the PPDU was partially or fully decoded).
+
+This trace helper collects records of all Wi-Fi PPDus received on every PHY that is enabled
+for the helper.  As an example, consider the scenario in Figure :ref:`wifi-phy-rx-trace-helper`,
+depicting the arrival of three PPDUs that overlap in time.  The trace helper keeps a record
+of each PPDU arrival, on each enabled PHY, and also keeps track of the PPDUs that collided
+with it, if any.  In the figure, the first PPDU overlaps in time with both the second and
+third PPDU.   Likewise, the second PPDU overlaps in time with the first and third PPDUs, and
+the third PPDU overlaps in time with the first and second.  All of these relationships (each
+frame arrival, the frames that overlapped in time with it), from the perspective of each
+PHY, are stored in internal data structures.  Additionally, the reception outcome of each
+PPDU, and its constituent MPDUs, is tracked.  This database of reception events can be
+exported by the trace helper for fine-grained tabulation of spatial reuse events of interest,
+or can be summarized by some built-in statistics printing methods.
+
+.. _wifi-phy-rx-trace-helper:
+
+.. figure:: figures/wifi-phy-rx-trace-helper.*
+
+   *WifiPhyRxTraceHelper scenario of interest*
+
+The output of this trace helper is provided in three formats:
+
+1) Built-in print methods to allow printing of key statistics with a single C++ statement,
+
+2) Export of a trace statistics object allowing the user to post-process or format the
+   data according to the user's formatting choice, and
+
+3) Export of the complete reception records, allowing the user to perform their own
+   custom processing of the data.
+
+A sample usage of this trace helper is as follows, as demonstrated in the example program
+``src/wifi/examples/wifi-phy-rx-trace-helper-example.cc``.  First, declare an instance
+of it as one might do with other Wi-Fi helpers:
+
+.. sourcecode:: cpp
+
+  WifiPhyRxTraceHelper rxTraceHelper;
+
+You may need to include the trace helper's header if it is not otherwise included by the
+wifi module header:
+
+.. sourcecode:: cpp
+
+  #include "ns3/wifi-phy-rx-trace-helper.h"
+
+Next, enable the trace helper on some subset of the Wi-Fi nodes in the simulation.  This step
+will hook traces on all of the nodes enabled.  It is important to include all of the nodes
+within reception range of the nodes of interest, because PPDUs need to be traced at
+both transmission and reception times.  If you are only interested in statistics or records
+on a given receiver, you can later (as explained below) request for only the statistics
+of interest.  For example, if you are interested in a particular AP, in a particular BSS,
+and there is an interfering BSS nearby, you will want to enable all of the nodes within
+interference range of the AP of interest (even if not in the same BSS).  So, in general,
+you will want to ``Enable()`` the trace helper on all Wi-Fi nodes in the simulation,
+unless you want to explore pruning this set for runtime scaling reasons.
+
+In this example, we will enable on all of the Wi-Fi nodes:
+
+.. sourcecode:: cpp
+
+    NodeContainer c;
+    c.Create(2);
+
+    ...
+
+    NetDeviceContainer apDevice = wifi.Install(wifiPhy, wifiMac, c.Get(1));
+    NetDeviceContainer staDevice = wifi.Install(wifiPhy, wifiMac, c.Get(0));
+
+    ...
+
+    rxTraceHelper.Enable(c);
+
+The important thing to note in the above is that ``Enable()`` must be called after
+Wi-Fi devices are installed, because it will hook traces on what has been installed
+up to that point.
+
+The next configuration aspect is to establish a start and stop time for PPDU reception
+collection.  In the example program, application data is not sent before 1 second,
+and we want to capture all data PPDUs, so the ``Start()`` and ``Stop()`` times are set
+as follows:
+
+.. sourcecode:: cpp
+
+    rxTraceHelper.Start(Seconds(1));
+    // The last packet will be sent at time 1 sec. + (numPackets - 1) * interval
+    // Configure the stop time to be 1 sec. later than this.
+    Time stopTime = Seconds(1) + (numPackets - 1) * interval + Seconds(1);
+    rxTraceHelper.Stop(stopTime);
+
+The start and stop times can be tuned to whatever collection window is desired.  Furthermore,
+there is a ``Reset()`` method that will clear all of the PPDU records and restart collection;
+this can be used if one wants to periodically sample the statistics in different time
+intervals.
+
+Next, run the simulation, and either during the run or after the simulation has completed,
+harvest the statistics.  As noted above, there are three main ways to output data.
+Furthermore, there are C++ method overloads that allow users to narrow the scope of
+output data.
+
+The first option is to use ``PrintStatistics()``, which will dump some statistics with
+built-in formatting, such as follows:
+
+.. sourcecode:: cpp
+
+    traceHelper.PrintStatistics();
+
+This will result in a number of statistics being printed out.  The statistics will
+be aggregated for all nodes that are enabled.  The following is some of the default
+output of the sample program:
+
+.. sourcecode:: text
+
+   *** Print statistics for all nodes using built-in print method:
+   Total PPDUs Received: 1
+   Total Non-Overlapping PPDUs Received: 1
+   Total Overlapping PPDUs Received: 0
+
+   Successful PPDUs: 1
+   Failed PPDUs: 0
+
+   Total MPDUs: 1
+   Total Successful MPDUs: 1
+   Total Failed MPDUs: 0
+
+
+In the above simple case, there is one PPDU successfully received, and within this PPDU,
+there was one MPDU which was successfully decoded.  No other PPDUs overlapped in time
+with this PPDU.
+
+Although this is a PHY trace helper, there is one important aspect from the MAC layer
+that is used to classify PPDUs.  When reporting statistics for a given node, a PPDU
+is counted only if there was at least one MPDU intended for the node.  If the MPDU
+has a MAC address that is either broadcast or belongs to the device (unicast), that
+PPDU will be counted.  If, instead, a receiver locks onto and overhears a PPDU
+that ultimately will be discarded because the receiver was not an intended receiver, that
+PPDU reception or failure will be excluded from the statistics.
+
+The sample program next shows how ``PrintStatistics`` can take an argument:
+
+.. sourcecode:: cpp
+
+    rxTraceHelper.PrintStatistics(c.Get(0)->GetId());
+    rxTraceHelper.PrintStatistics(c.Get(1));
+
+In the above, the statistics can be limited to a particular node (either passed in
+by Node ID or by Node pointer).  Furthermore, although not shown in the example,
+the method can be further downscoped to also take a device index argument and
+(in the case of multi-link operation (MLO)) a specific link ID.  In the above example,
+all devices and all MLO links will be included in the output.
+
+Users can write their own printing methods or further process the statistics by
+calling ``GetStatistics()`` as the following example demonstrates:
+
+.. sourcecode:: cpp
+
+    auto stats = rxTraceHelper.GetStatistics();
+    std::cout << "  numOverlapppingPpdu: " << stats.m_numOverlappingPpdu << std::endl;
+    std::cout << "  numNonOverlapppingPpdu: " << stats.m_numNonOverlappingPpdu << std::endl;
+    std::cout << "  numPpduFailed: " << stats.m_numPpduFailed << std::endl;
+    std::cout << "  numPpduSuccess: " << stats.m_numPpduSuccess << std::endl;
+    std::cout << "  numMpduSuccess: " << stats.m_numMpduSuccess << std::endl;
+    std::cout << "  numMpduFailed: " << stats.m_numMpduFailed << std::endl;
+
+Similar to ``PrintStatistics()``, ``GetStatistics()`` with no arguments will collect
+a statistics output structure covering all nodes, while additional arguments of
+Node ID, device index, and link ID can be used to constrain the statistics report.
+
+Finally, the output of the internal data structure that tracks PPDU receptions can
+be exported, with the ``GetPpduRecords()`` method, which can be called
+without any arguments, and with arguments of nodeId, deviceId, and linkId:
+
+.. sourcecode:: cpp
+
+    auto optionalRecords = rxTraceHelper.GetPpduRecords(1);
+
+The above statements asks for records from receiving node 1 (the AP).  The example
+iterates the returned vector, printing out the size of this structure, as well
+as some data fields:
+
+.. sourcecode:: text
+
+  *** Records vector has size of 3
+  First record:
+    first PPDU's RSSI (dBm): -30.6633
+    first PPDU's receiver ID: 1
+    first PPDU's sender ID: 0
+    first PPDU's start time: 1
+    first PPDU's end time: 1.00008
+    first PPDU's number of MPDUs: 1
+    first PPDU's sender device ID: 0
+  Second record:
+    second PPDU's RSSI (dBm): -30.6633
+    second PPDU's receiver ID: 1
+    second PPDU's sender ID: 0
+    second PPDU's start time: 1.00027
+    second PPDU's end time: 1.00032
+    second PPDU's number of MPDUs: 1
+    second PPDU's sender device ID: 0
+  Third record:
+    third PPDU's RSSI (dBm): -30.6633
+    third PPDU's receiver ID: 1
+    third PPDU's sender ID: 0
+    third PPDU's start time: 1.00039
+    third PPDU's end time: 1.00072
+    third PPDU's number of MPDUs: 1
+    third PPDU's sender device ID: 0
+
+That the size of the vector is 3 may be surprising, considering that we have observed
+above in this example that only one PPDU is being counted in the statistics.  However,
+in this example, there is only one data PPDU but also additional management and control
+frames.  Specifically, the first PPDU is a Block ACK ADDBA_REQUEST frame, the second PPDU
+is an ACK of the AP's ADDBA_RESPONSE frame, and the third PPDU record corresponds to the
+actual data PPDU, starting at time 1.00039 and ending at 1.00072.
+The management and control frames (which also include beacons) are filtered out above by
+the ``GetStatistics()`` methods, but when the raw PPDU records are retrieved, all PPDUs
+received are available and the user is responsible for further filtering as they see fit.
+
 HT configuration
 ================
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/examples/CMakeLists.txt ns-3.42/src/wifi/examples/CMakeLists.txt
--- ns-3.41/src/wifi/examples/CMakeLists.txt	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/examples/CMakeLists.txt	2024-05-29 15:29:47.196073800 -0700
@@ -57,3 +57,12 @@
     ${libapplications}
     ${libinternet-apps}
 )
+
+build_lib_example(
+  NAME wifi-phy-rx-trace-example
+  SOURCE_FILES wifi-phy-rx-trace-example.cc
+  LIBRARIES_TO_LINK
+    ${libwifi}
+    ${libinternet}
+    ${libmobility}
+)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/examples/wifi-bianchi.cc ns-3.42/src/wifi/examples/wifi-bianchi.cc
--- ns-3.41/src/wifi/examples/wifi-bianchi.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/examples/wifi-bianchi.cc	2024-05-29 15:29:47.196073800 -0700
@@ -53,6 +53,7 @@
 #include "ns3/yans-wifi-helper.h"
 
 #include <fstream>
+#include <vector>
 
 /// Avoid std::numbers::pi because it's C++20
 #define PI 3.1415926535
@@ -2166,6 +2167,8 @@
     case OBSS_PD_CCA_RESET:
         NS_FATAL_ERROR("Unexpected CCA reset!");
         break;
+    case SIGNAL_DETECTION_ABORTED_BY_TX:
+        break;
     case UNKNOWN:
     default:
         NS_FATAL_ERROR("Unknown drop reason!");
@@ -2866,11 +2869,7 @@
     }
     else if (standard == "11n")
     {
-        if (frequency == 2.4)
-        {
-            wifiStandard = WIFI_STANDARD_80211n;
-        }
-        else if (frequency == 5)
+        if (frequency == 2.4 || frequency == 5)
         {
             wifiStandard = WIFI_STANDARD_80211n;
         }
@@ -2887,15 +2886,7 @@
     }
     else if (standard == "11ax")
     {
-        if (frequency == 2.4)
-        {
-            wifiStandard = WIFI_STANDARD_80211ax;
-        }
-        else if (frequency == 5)
-        {
-            wifiStandard = WIFI_STANDARD_80211ax;
-        }
-        else if (frequency == 6)
+        if (frequency == 2.4 || frequency == 5 || frequency == 6)
         {
             wifiStandard = WIFI_STANDARD_80211ax;
         }
@@ -2972,7 +2963,7 @@
     Experiment experiment;
     WifiMacHelper wifiMac;
     double averageThroughput;
-    double throughputArray[trials];
+    std::vector<double> throughputArray(trials);
     for (uint32_t n = nMinStas; n <= nMaxStas; n += nStepSize)
     {
         averageThroughput = 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/examples/wifi-manager-example.cc ns-3.42/src/wifi/examples/wifi-manager-example.cc
--- ns-3.41/src/wifi/examples/wifi-manager-example.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/examples/wifi-manager-example.cc	2024-05-29 15:29:47.196073800 -0700
@@ -65,6 +65,7 @@
 #include "ns3/ssid.h"
 #include "ns3/tuple.h"
 #include "ns3/uinteger.h"
+#include "ns3/wifi-mac.h"
 #include "ns3/wifi-net-device.h"
 #include "ns3/yans-wifi-helper.h"
 
@@ -230,6 +231,9 @@
     uint32_t maxSlrc = 7;
     uint32_t maxSsrc = 7;
 
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(2);
+
     CommandLine cmd(__FILE__);
     cmd.AddValue("maxSsrc",
                  "The maximum number of retransmission attempts for a RTS packet",
@@ -673,10 +677,8 @@
         clientDevice = wifi.Install(wifiPhy, wifiMac, clientNode);
     }
 
-    RngSeedManager::SetSeed(1);
-    RngSeedManager::SetRun(2);
     wifi.AssignStreams(serverDevice, 100);
-    wifi.AssignStreams(clientDevice, 100);
+    wifi.AssignStreams(clientDevice, 200);
 
     Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/BE_MaxAmpduSize",
                 UintegerValue(maxAmpduSize));
@@ -798,6 +800,16 @@
 
     Simulator::Stop(Seconds((steps + 1) * stepTime));
     Simulator::Run();
+
+    if (serverSelectedStandard.m_standard >= WIFI_STANDARD_80211n)
+    {
+        NS_ABORT_MSG_UNLESS(wndClient->GetMac()->GetBaAgreementEstablishedAsOriginator(
+                                wndServer->GetMac()->GetAddress(),
+                                0),
+                            "Expected BA agreement established for standard "
+                                << serverSelectedStandard.m_standard);
+    }
+
     Simulator::Destroy();
 
     gnuplot.AddDataset(rateDataset);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/examples/wifi-phy-configuration.cc ns-3.42/src/wifi/examples/wifi-phy-configuration.cc
--- ns-3.41/src/wifi/examples/wifi-phy-configuration.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/examples/wifi-phy-configuration.cc	2024-05-29 15:29:47.196073800 -0700
@@ -479,4 +479,6 @@
 
     // No need to Simulator::Run (); this is a configuration example
     Simulator::Destroy();
+
+    return 0;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/examples/wifi-phy-rx-trace-example.cc ns-3.42/src/wifi/examples/wifi-phy-rx-trace-example.cc
--- ns-3.41/src/wifi/examples/wifi-phy-rx-trace-example.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/examples/wifi-phy-rx-trace-example.cc	2024-05-29 15:29:47.196073800 -0700
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2009 The Boeing Company
+ * Copyright (c) 2024 University of Washington (updated to 802.11ax standard)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+// The purpose of this example is to illustrate basic use of the
+// WifiPhyRxTraceHelper on a simple example program.
+//
+// This script configures two 802.11ax Wi-Fi nodes on a YansWifiChannel,
+// with devices in infrastructure mode, and by default, the station sends
+// one packet of 1000 (application) bytes to the access point.  A simple
+// free-space path loss (Friis) propagation loss model is configured.
+// The lowest MCS ("HeMcs0") value is configured.
+//
+// The first packet is sent at time 1 sec.  If more packets are configured
+// to be sent, they are separated in time by the 'interval' parameter, which
+// defaults to 1 sec.  The simulation ends 1 sec. after the last packet is sent.
+//
+// This script can also be used to put the Wifi layer into full logging mode
+// at the LOG_LEVEL_INFO level; this command will turn on all logging in the
+// wifi module:
+//
+// ./ns3 run "wifi-phy-rx-trace-example --logging=1"
+//
+// Logging of the example program itself is enabled by default in this program;
+// to turn off the printing of packet send and receive events, disable the verbose mode:
+//
+// ./ns3 run "wifi-phy-rx-trace-example --verbose=0"
+//
+// When you are done, you will notice two pcap trace files in your directory.
+// If you have tcpdump installed, you can try this:
+//
+// tcpdump -r wifi-phy-rx-trace-example-0-0.pcap -nn -tt
+//
+// The STA is indexed as node 0, the AP is indexed as node 1
+//
+// Additionally, an ASCII trace file is created (wifi-phy-rx-trace-example.tr)
+//
+// Finally, the example demonstrates that two independent BSS can exist on the
+// same channel, with the trace helper configured to log rxs only on one
+// of the BSS.  The outside BSS (OBSS) will send packets that are picked up
+// by the trace helper on the primary BSS's devices.  The distance to the OBSS
+// can be configured to place the OBSS within or outside of carrier sense range.
+// The command-line options 'enableTwoBss' and 'distanceTwoBss' can be used
+// to optionally enable and configure the second BSS.
+
+#include "ns3/command-line.h"
+#include "ns3/config.h"
+#include "ns3/double.h"
+#include "ns3/internet-stack-helper.h"
+#include "ns3/ipv4-address-helper.h"
+#include "ns3/log.h"
+#include "ns3/mobility-helper.h"
+#include "ns3/mobility-model.h"
+#include "ns3/neighbor-cache-helper.h"
+#include "ns3/ssid.h"
+#include "ns3/string.h"
+#include "ns3/wifi-phy-rx-trace-helper.h"
+#include "ns3/yans-wifi-channel.h"
+#include "ns3/yans-wifi-helper.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("WifiPhyRxTraceExample");
+
+/**
+ * Function called when a packet is received.
+ *
+ * \param socket The receiving socket.
+ */
+void
+ReceivePacket(Ptr<Socket> socket)
+{
+    Ptr<Packet> p;
+    while ((p = socket->Recv()))
+    {
+        NS_LOG_INFO("Received packet with size " << p->GetSize());
+    }
+}
+
+void
+ReceiveObssPacket(Ptr<Socket> socket)
+{
+    Ptr<Packet> p;
+    while ((p = socket->Recv()))
+    {
+        NS_LOG_INFO("Received packet on OBSS network with size " << p->GetSize());
+    }
+}
+
+/**
+ * Generate traffic.
+ *
+ * \param socket The sending socket.
+ * \param pktSize The packet size.
+ * \param pktCount The packet count.
+ * \param pktInterval The interval between two packets.
+ */
+static void
+GeneratePacket(Ptr<Socket> socket, uint32_t pktSize, uint32_t pktCount, Time pktInterval)
+{
+    if (pktCount > 0)
+    {
+        NS_LOG_INFO("Generating packet of size " << pktSize);
+        socket->Send(Create<Packet>(pktSize));
+        Simulator::Schedule(pktInterval,
+                            &GeneratePacket,
+                            socket,
+                            pktSize,
+                            pktCount - 1,
+                            pktInterval);
+    }
+    else
+    {
+        socket->Close();
+    }
+}
+
+void
+PopulateNeighborCache()
+{
+    NeighborCacheHelper neighborCache;
+    neighborCache.PopulateNeighborCache();
+}
+
+int
+main(int argc, char* argv[])
+{
+    uint32_t packetSize = 1000; // bytes
+    uint32_t numPackets = 1;
+    double distance = 1;        // meters
+    bool enableTwoBss = false;  // whether to enable a second (non-traced) BSS
+    double distanceTwoBss = 10; // meters (distance between APs if enableTwoBss is true)
+    Time interval = Seconds(1.0);
+    bool verbose = true;
+    bool logging = false;
+
+    CommandLine cmd(__FILE__);
+    cmd.AddValue("packetSize", "size of application packet sent", packetSize);
+    cmd.AddValue("numPackets", "number of packets generated", numPackets);
+    cmd.AddValue("interval", "interval between packets", interval);
+    cmd.AddValue("distance", "distance between AP and STA", distance);
+    cmd.AddValue("enableTwoBss", "enable a second BSS (not traced)", enableTwoBss);
+    cmd.AddValue("distanceTwoBss", "distance between BSS (meters)", distanceTwoBss);
+    cmd.AddValue("logging", "enable all wifi module log components", logging);
+    cmd.AddValue("verbose", "enable this program's log components", verbose);
+    cmd.Parse(argc, argv);
+
+    if (numPackets == 0)
+    {
+        std::cout << "No packets configured to be sent; exiting" << std::endl;
+        return 0;
+    }
+
+    NodeContainer c;
+    c.Create(2);
+
+    NodeContainer c2;
+    if (enableTwoBss)
+    {
+        c2.Create(2);
+    }
+
+    MobilityHelper mobility;
+    Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator>();
+    positionAlloc->Add(Vector(0.0, 0.0, 0.0));
+    positionAlloc->Add(Vector(distance, 0.0, 0.0));
+    mobility.SetPositionAllocator(positionAlloc);
+    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+    mobility.Install(c);
+
+    if (enableTwoBss)
+    {
+        MobilityHelper obssMobility;
+        Ptr<ListPositionAllocator> obssPositionAlloc = CreateObject<ListPositionAllocator>();
+        obssPositionAlloc->Add(Vector(0.0, distanceTwoBss, 0.0));
+        obssPositionAlloc->Add(Vector(distance, distanceTwoBss, 0.0));
+        obssMobility.SetPositionAllocator(obssPositionAlloc);
+        obssMobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+        obssMobility.Install(c2);
+    }
+
+    WifiHelper wifi;
+    wifi.SetStandard(WIFI_STANDARD_80211ax);
+
+    YansWifiPhyHelper wifiPhy;
+    wifiPhy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
+
+    YansWifiChannelHelper wifiChannel;
+    wifiChannel.SetPropagationDelay("ns3::ConstantSpeedPropagationDelayModel");
+    wifiChannel.AddPropagationLoss("ns3::FriisPropagationLossModel");
+    wifiPhy.SetChannel(wifiChannel.Create());
+
+    // Add a mac and disable rate control
+    WifiMacHelper wifiMac;
+    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
+                                 "DataMode",
+                                 StringValue("HeMcs0"),
+                                 "ControlMode",
+                                 StringValue("HeMcs0"));
+
+    // Setup the rest of the MAC
+    Ssid ssid = Ssid("wifi-default");
+    // setup STA
+    wifiMac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid));
+    NetDeviceContainer staDevice = wifi.Install(wifiPhy, wifiMac, c.Get(0));
+    NetDeviceContainer devices = staDevice;
+    // setup AP to beacon roughly once per second (must be a multiple of 1024 us)
+    wifiMac.SetType("ns3::ApWifiMac",
+                    "Ssid",
+                    SsidValue(ssid),
+                    "BeaconInterval",
+                    TimeValue(MilliSeconds(1024)));
+    NetDeviceContainer apDevice = wifi.Install(wifiPhy, wifiMac, c.Get(1));
+    devices.Add(apDevice);
+
+    NetDeviceContainer obssDevices;
+    if (enableTwoBss)
+    {
+        ssid = Ssid("obss");
+        wifiMac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid));
+        NetDeviceContainer obssStaDevice = wifi.Install(wifiPhy, wifiMac, c2.Get(0));
+        obssDevices = obssStaDevice;
+        wifiMac.SetType("ns3::ApWifiMac",
+                        "Ssid",
+                        SsidValue(ssid),
+                        "BeaconInterval",
+                        TimeValue(MilliSeconds(1024)));
+        NetDeviceContainer obssApDevice = wifi.Install(wifiPhy, wifiMac, c2.Get(1));
+        obssDevices.Add(obssApDevice);
+    }
+
+    InternetStackHelper internet;
+    internet.Install(c);
+
+    Ipv4AddressHelper ipv4;
+    ipv4.SetBase("10.1.1.0", "255.255.255.0");
+    Ipv4InterfaceContainer i = ipv4.Assign(devices);
+
+    if (enableTwoBss)
+    {
+        internet.Install(c2);
+        ipv4.SetBase("10.1.2.0", "255.255.255.0");
+        ipv4.Assign(obssDevices);
+    }
+
+    TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
+    Ptr<Socket> recvSink = Socket::CreateSocket(c.Get(1), tid);
+    InetSocketAddress local = InetSocketAddress(Ipv4Address::GetAny(), 80);
+    recvSink->Bind(local);
+    recvSink->SetRecvCallback(MakeCallback(&ReceivePacket));
+
+    Ptr<Socket> source = Socket::CreateSocket(c.Get(0), tid);
+    InetSocketAddress remote = InetSocketAddress(Ipv4Address("10.1.1.2"), 80);
+    source->Connect(remote);
+
+    Ptr<Socket> obssRecvSink;
+    Ptr<Socket> obssSource;
+    if (enableTwoBss)
+    {
+        obssRecvSink = Socket::CreateSocket(c2.Get(1), tid);
+        InetSocketAddress obssLocal = InetSocketAddress(Ipv4Address::GetAny(), 80);
+        obssRecvSink->Bind(obssLocal);
+        obssRecvSink->SetRecvCallback(MakeCallback(&ReceiveObssPacket));
+
+        obssSource = Socket::CreateSocket(c2.Get(0), tid);
+        InetSocketAddress obssRemote = InetSocketAddress(Ipv4Address("10.1.2.2"), 80);
+        obssSource->Connect(obssRemote);
+    }
+
+    // Use the NeighborCacheHelper to avoid ARP messages (ARP replies, since they are unicast,
+    // count in the statistics.  The cache operation must be scheduled after WifiNetDevices are
+    // started, until issue #851 is fixed.  The indirection through a normal function is
+    // necessary because NeighborCacheHelper::PopulateNeighborCache() is overloaded
+    Simulator::Schedule(Seconds(0.99), &PopulateNeighborCache);
+
+    // Tracing
+    wifiPhy.EnablePcap("wifi-phy-rx-trace-example", devices);
+    AsciiTraceHelper asciiTrace;
+    wifiPhy.EnableAsciiAll(asciiTrace.CreateFileStream("wifi-phy-rx-trace-example.tr"));
+
+    // Logging configuration
+    if (logging)
+    {
+        WifiHelper::EnableLogComponents(LOG_LEVEL_INFO); // Turn on all Wifi logging
+    }
+    if (verbose)
+    {
+        LogComponentEnable(
+            "WifiPhyRxTraceExample",
+            (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_NODE | LOG_PREFIX_TIME | LOG_LEVEL_ALL));
+    }
+    WifiPhyRxTraceHelper rxTraceHelper;
+    // Enable trace helper only on one BSS
+    rxTraceHelper.Enable(c);
+    rxTraceHelper.Start(MilliSeconds(999)); // 1 ms before applications
+    // The last packet will be sent at time 1 sec. + (numPackets - 1) * interval
+    // Configure the stop time to be 1 sec. later than this.
+    Time stopTime = Seconds(1) + (numPackets - 1) * interval + Seconds(1);
+    rxTraceHelper.Stop(stopTime);
+
+    Simulator::ScheduleWithContext(source->GetNode()->GetId(),
+                                   Seconds(1.0),
+                                   &GeneratePacket,
+                                   source,
+                                   packetSize,
+                                   numPackets,
+                                   interval);
+
+    if (enableTwoBss)
+    {
+        Simulator::ScheduleWithContext(obssSource->GetNode()->GetId(),
+                                       Seconds(1.5),
+                                       &GeneratePacket,
+                                       obssSource,
+                                       packetSize,
+                                       numPackets,
+                                       interval);
+    }
+
+    Simulator::Stop(stopTime);
+    Simulator::Run();
+
+    // The following provide some examples of how to access and print the trace helper contents.
+
+    std::cout << "*** Print statistics for all nodes using built-in print method:" << std::endl;
+    rxTraceHelper.PrintStatistics();
+    std::cout << std::endl;
+
+    std::cout << "*** Print statistics for the STA only using built-in print method:" << std::endl;
+    rxTraceHelper.PrintStatistics(c.Get(0)->GetId());
+    std::cout << std::endl;
+
+    std::cout << "*** Print statistics for the AP only using built-in print method:" << std::endl;
+    rxTraceHelper.PrintStatistics(c.Get(1));
+    std::cout << std::endl;
+
+    std::cout << "*** Get statistics object and print the fields one-by-one:" << std::endl;
+    auto stats = rxTraceHelper.GetStatistics();
+    std::cout << "  overlapppingPpdu: " << stats.m_overlappingPpdus << std::endl;
+    std::cout << "  nonOverlapppingPpdu: " << stats.m_nonOverlappingPpdus << std::endl;
+    std::cout << "  receivedPpdus: " << stats.m_receivedPpdus << std::endl;
+    std::cout << "  failedPpdus: " << stats.m_failedPpdus << std::endl;
+    std::cout << "  receivedMpdus: " << stats.m_receivedMpdus << std::endl;
+    std::cout << "  failedMpdus: " << stats.m_failedMpdus << std::endl;
+    std::cout << std::endl;
+
+    std::cout << "*** Get vector of reception records and print out some fields:" << std::endl;
+    auto optionalRecords = rxTraceHelper.GetPpduRecords(1);
+    if (optionalRecords.has_value())
+    {
+        auto records = optionalRecords->get(); // const std::vector<WifiPpduRxRecord>&
+        std::cout << "*** Records vector has size of " << records.size() << std::endl;
+        if (!records.empty())
+        {
+            // First record
+            std::cout << "  First record:" << std::endl;
+            std::cout << "    first PPDU's RSSI (dBm): " << records[0].m_rssi << std::endl;
+            std::cout << "    first PPDU's receiver ID: " << records[0].m_receiverId << std::endl;
+            std::cout << "    first PPDU's sender ID: " << records[0].m_senderId << std::endl;
+            std::cout << "    first PPDU's start time: " << records[0].m_startTime.GetSeconds()
+                      << std::endl;
+            std::cout << "    first PPDU's end time: " << records[0].m_endTime.GetSeconds()
+                      << std::endl;
+            std::cout << "    first PPDU's number of MPDUs: " << records[0].m_statusPerMpdu.size()
+                      << std::endl;
+            std::cout << "    first PPDU's sender device ID: " << records[0].m_senderDeviceId
+                      << std::endl;
+        }
+        if (records.size() > 1)
+        {
+            // Second record
+            std::cout << "  Second record:" << std::endl;
+            std::cout << "    second PPDU's RSSI (dBm): " << records[1].m_rssi << std::endl;
+            std::cout << "    second PPDU's receiver ID: " << records[1].m_receiverId << std::endl;
+            std::cout << "    second PPDU's sender ID: " << records[1].m_senderId << std::endl;
+            std::cout << "    second PPDU's start time: " << records[1].m_startTime.GetSeconds()
+                      << std::endl;
+            std::cout << "    second PPDU's end time: " << records[1].m_endTime.GetSeconds()
+                      << std::endl;
+            std::cout << "    second PPDU's number of MPDUs: " << records[1].m_statusPerMpdu.size()
+                      << std::endl;
+            std::cout << "    second PPDU's sender device ID: " << records[1].m_senderDeviceId
+                      << std::endl;
+        }
+        if (records.size() > 2)
+        {
+            // Third record
+            std::cout << "  Third record:" << std::endl;
+            std::cout << "    third PPDU's RSSI (dBm): " << records[2].m_rssi << std::endl;
+            std::cout << "    third PPDU's receiver ID: " << records[2].m_receiverId << std::endl;
+            std::cout << "    third PPDU's sender ID: " << records[2].m_senderId << std::endl;
+            std::cout << "    third PPDU's start time: " << records[2].m_startTime.GetSeconds()
+                      << std::endl;
+            std::cout << "    third PPDU's end time: " << records[2].m_endTime.GetSeconds()
+                      << std::endl;
+            std::cout << "    third PPDU's number of MPDUs: " << records[2].m_statusPerMpdu.size()
+                      << std::endl;
+            std::cout << "    third PPDU's sender device ID: " << records[2].m_senderDeviceId
+                      << std::endl;
+        }
+        std::cout << std::endl;
+    }
+    else
+    {
+        std::cout << "*** Records vector is empty" << std::endl;
+        std::cout << std::endl;
+    }
+
+    Simulator::Destroy();
+
+    return 0;
+}
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/examples/wifi-test-interference-helper.cc ns-3.42/src/wifi/examples/wifi-test-interference-helper.cc
--- ns-3.41/src/wifi/examples/wifi-test-interference-helper.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/examples/wifi-test-interference-helper.cc	2024-05-29 15:29:47.196073800 -0700
@@ -44,7 +44,7 @@
 // Note that the program checks the consistency between the selected standard
 // the selected preamble type.
 //
-// The output of the program displays InterfenceHelper and SpectrumWifiPhy trace
+// The output of the program displays InterferenceHelper and SpectrumWifiPhy trace
 // logs associated to the chosen scenario.
 //
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/spectrum-wifi-helper.cc ns-3.42/src/wifi/helper/spectrum-wifi-helper.cc
--- ns-3.41/src/wifi/helper/spectrum-wifi-helper.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/spectrum-wifi-helper.cc	2024-05-29 15:29:47.196073800 -0700
@@ -160,7 +160,7 @@
 void
 SpectrumWifiPhyHelper::InstallPhyInterfaces(uint8_t linkId, Ptr<SpectrumWifiPhy> phy) const
 {
-    if (m_interfacesMap.count(linkId) == 0)
+    if (!m_interfacesMap.contains(linkId))
     {
         // default setup: set all interfaces to this link
         for (const auto& [freqRange, channel] : m_channels)
@@ -195,7 +195,7 @@
             continue;
         }
         if (const auto& interfaces = spectrumPhy->GetSpectrumPhyInterfaces();
-            interfaces.count(phy->GetCurrentFrequencyRange()) == 0)
+            !interfaces.contains(phy->GetCurrentFrequencyRange()))
         {
             // no interface attached to that channel
             continue;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-helper.cc ns-3.42/src/wifi/helper/wifi-helper.cc
--- ns-3.41/src/wifi/helper/wifi-helper.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/wifi-helper.cc	2024-05-29 15:29:47.196073800 -0700
@@ -877,111 +877,109 @@
 }
 
 void
-WifiHelper::EnableLogComponents()
+WifiHelper::EnableLogComponents(LogLevel logLevel)
 {
     LogComponentEnableAll(LOG_PREFIX_TIME);
     LogComponentEnableAll(LOG_PREFIX_NODE);
 
-    LogComponentEnable("AarfWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("AarfcdWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("AdhocWifiMac", LOG_LEVEL_ALL);
-    LogComponentEnable("AmrrWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("ApWifiMac", LOG_LEVEL_ALL);
-    LogComponentEnable("AparfWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("ArfWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("BlockAckAgreement", LOG_LEVEL_ALL);
-    LogComponentEnable("BlockAckManager", LOG_LEVEL_ALL);
-    LogComponentEnable("CaraWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("ChannelAccessManager", LOG_LEVEL_ALL);
-    LogComponentEnable("ConstantObssPdAlgorithm", LOG_LEVEL_ALL);
-    LogComponentEnable("ConstantRateWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("DefaultEmlsrManager", LOG_LEVEL_ALL);
-    LogComponentEnable("DsssErrorRateModel", LOG_LEVEL_ALL);
-    LogComponentEnable("DsssPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("DsssPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("EhtFrameExchangeManager", LOG_LEVEL_ALL);
-    LogComponentEnable("EhtPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("EhtPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("EmlsrManager", LOG_LEVEL_ALL);
-    LogComponentEnable("ErpOfdmPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("ErpOfdmPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("FrameExchangeManager", LOG_LEVEL_ALL);
-    LogComponentEnable("HeConfiguration", LOG_LEVEL_ALL);
-    LogComponentEnable("HeFrameExchangeManager", LOG_LEVEL_ALL);
-    LogComponentEnable("HePhy", LOG_LEVEL_ALL);
-    LogComponentEnable("HePpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("HtConfiguration", LOG_LEVEL_ALL);
-    LogComponentEnable("HtFrameExchangeManager", LOG_LEVEL_ALL);
-    LogComponentEnable("HtPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("HtPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("IdealWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("InterferenceHelper", LOG_LEVEL_ALL);
-    LogComponentEnable("MacRxMiddle", LOG_LEVEL_ALL);
-    LogComponentEnable("MacTxMiddle", LOG_LEVEL_ALL);
-    LogComponentEnable("MinstrelHtWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("MinstrelWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("MpduAggregator", LOG_LEVEL_ALL);
-    LogComponentEnable("MsduAggregator", LOG_LEVEL_ALL);
-    LogComponentEnable("MultiUserScheduler", LOG_LEVEL_ALL);
-    LogComponentEnable("NistErrorRateModel", LOG_LEVEL_ALL);
-    LogComponentEnable("ObssPdAlgorithm", LOG_LEVEL_ALL);
-    LogComponentEnable("OfdmPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("OfdmPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("OnoeWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("OriginatorBlockAckAgreement", LOG_LEVEL_ALL);
-    LogComponentEnable("ParfWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("PhyEntity", LOG_LEVEL_ALL);
-    LogComponentEnable("QosFrameExchangeManager", LOG_LEVEL_ALL);
-    LogComponentEnable("QosTxop", LOG_LEVEL_ALL);
-    LogComponentEnable("RecipientBlockAckAgreement", LOG_LEVEL_ALL);
-    LogComponentEnable("RrMultiUserScheduler", LOG_LEVEL_ALL);
-    LogComponentEnable("RraaWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("RrpaaWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("SimpleFrameCaptureModel", LOG_LEVEL_ALL);
-    LogComponentEnable("SpectrumWifiPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("StaWifiMac", LOG_LEVEL_ALL);
-    LogComponentEnable("SupportedRates", LOG_LEVEL_ALL);
-    LogComponentEnable("TableBasedErrorRateModel", LOG_LEVEL_ALL);
-    LogComponentEnable("ThompsonSamplingWifiManager", LOG_LEVEL_ALL);
-    LogComponentEnable("ThresholdPreambleDetectionModel", LOG_LEVEL_ALL);
-    LogComponentEnable("Txop", LOG_LEVEL_ALL);
-    LogComponentEnable("VhtConfiguration", LOG_LEVEL_ALL);
-    LogComponentEnable("VhtFrameExchangeManager", LOG_LEVEL_ALL);
-    LogComponentEnable("VhtPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("VhtPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiAckManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiAssocManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiDefaultAckManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiDefaultAssocManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiDefaultProtectionManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiMac", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiMacQueue", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiMpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiNetDevice", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiPhyStateHelper", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiPhyOperatingChannel", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiPhy", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiPpdu", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiProtectionManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiPsdu", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiRadioEnergyModel", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiRemoteStationManager", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiSpectrumPhyInterface", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiSpectrumSignalParameters", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiTxCurrentModel", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiTxParameters", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiTxTimer", LOG_LEVEL_ALL);
-    LogComponentEnable("YansErrorRateModel", LOG_LEVEL_ALL);
-    LogComponentEnable("YansWifiChannel", LOG_LEVEL_ALL);
-    LogComponentEnable("YansWifiPhy", LOG_LEVEL_ALL);
+    LogComponentEnable("AarfWifiManager", logLevel);
+    LogComponentEnable("AarfcdWifiManager", logLevel);
+    LogComponentEnable("AdhocWifiMac", logLevel);
+    LogComponentEnable("AmrrWifiManager", logLevel);
+    LogComponentEnable("ApWifiMac", logLevel);
+    LogComponentEnable("AparfWifiManager", logLevel);
+    LogComponentEnable("ArfWifiManager", logLevel);
+    LogComponentEnable("BlockAckAgreement", logLevel);
+    LogComponentEnable("BlockAckManager", logLevel);
+    LogComponentEnable("CaraWifiManager", logLevel);
+    LogComponentEnable("ChannelAccessManager", logLevel);
+    LogComponentEnable("ConstantObssPdAlgorithm", logLevel);
+    LogComponentEnable("ConstantRateWifiManager", logLevel);
+    LogComponentEnable("DefaultEmlsrManager", logLevel);
+    LogComponentEnable("DsssErrorRateModel", logLevel);
+    LogComponentEnable("DsssPhy", logLevel);
+    LogComponentEnable("DsssPpdu", logLevel);
+    LogComponentEnable("EhtFrameExchangeManager", logLevel);
+    LogComponentEnable("EhtPhy", logLevel);
+    LogComponentEnable("EhtPpdu", logLevel);
+    LogComponentEnable("EmlsrManager", logLevel);
+    LogComponentEnable("ErpOfdmPhy", logLevel);
+    LogComponentEnable("ErpOfdmPpdu", logLevel);
+    LogComponentEnable("FrameExchangeManager", logLevel);
+    LogComponentEnable("HeConfiguration", logLevel);
+    LogComponentEnable("HeFrameExchangeManager", logLevel);
+    LogComponentEnable("HePhy", logLevel);
+    LogComponentEnable("HePpdu", logLevel);
+    LogComponentEnable("HtConfiguration", logLevel);
+    LogComponentEnable("HtFrameExchangeManager", logLevel);
+    LogComponentEnable("HtPhy", logLevel);
+    LogComponentEnable("HtPpdu", logLevel);
+    LogComponentEnable("IdealWifiManager", logLevel);
+    LogComponentEnable("InterferenceHelper", logLevel);
+    LogComponentEnable("MacRxMiddle", logLevel);
+    LogComponentEnable("MacTxMiddle", logLevel);
+    LogComponentEnable("MinstrelHtWifiManager", logLevel);
+    LogComponentEnable("MinstrelWifiManager", logLevel);
+    LogComponentEnable("MpduAggregator", logLevel);
+    LogComponentEnable("MsduAggregator", logLevel);
+    LogComponentEnable("MultiUserScheduler", logLevel);
+    LogComponentEnable("NistErrorRateModel", logLevel);
+    LogComponentEnable("ObssPdAlgorithm", logLevel);
+    LogComponentEnable("OfdmPhy", logLevel);
+    LogComponentEnable("OfdmPpdu", logLevel);
+    LogComponentEnable("OnoeWifiManager", logLevel);
+    LogComponentEnable("OriginatorBlockAckAgreement", logLevel);
+    LogComponentEnable("ParfWifiManager", logLevel);
+    LogComponentEnable("PhyEntity", logLevel);
+    LogComponentEnable("QosFrameExchangeManager", logLevel);
+    LogComponentEnable("QosTxop", logLevel);
+    LogComponentEnable("RecipientBlockAckAgreement", logLevel);
+    LogComponentEnable("RrMultiUserScheduler", logLevel);
+    LogComponentEnable("RraaWifiManager", logLevel);
+    LogComponentEnable("RrpaaWifiManager", logLevel);
+    LogComponentEnable("SimpleFrameCaptureModel", logLevel);
+    LogComponentEnable("SpectrumWifiPhy", logLevel);
+    LogComponentEnable("StaWifiMac", logLevel);
+    LogComponentEnable("SupportedRates", logLevel);
+    LogComponentEnable("TableBasedErrorRateModel", logLevel);
+    LogComponentEnable("ThompsonSamplingWifiManager", logLevel);
+    LogComponentEnable("ThresholdPreambleDetectionModel", logLevel);
+    LogComponentEnable("Txop", logLevel);
+    LogComponentEnable("VhtConfiguration", logLevel);
+    LogComponentEnable("VhtFrameExchangeManager", logLevel);
+    LogComponentEnable("VhtPhy", logLevel);
+    LogComponentEnable("VhtPpdu", logLevel);
+    LogComponentEnable("WifiAckManager", logLevel);
+    LogComponentEnable("WifiAssocManager", logLevel);
+    LogComponentEnable("WifiDefaultAckManager", logLevel);
+    LogComponentEnable("WifiDefaultAssocManager", logLevel);
+    LogComponentEnable("WifiDefaultProtectionManager", logLevel);
+    LogComponentEnable("WifiMac", logLevel);
+    LogComponentEnable("WifiMacQueue", logLevel);
+    LogComponentEnable("WifiMpdu", logLevel);
+    LogComponentEnable("WifiNetDevice", logLevel);
+    LogComponentEnable("WifiPhyStateHelper", logLevel);
+    LogComponentEnable("WifiPhyOperatingChannel", logLevel);
+    LogComponentEnable("WifiPhy", logLevel);
+    LogComponentEnable("WifiPpdu", logLevel);
+    LogComponentEnable("WifiProtectionManager", logLevel);
+    LogComponentEnable("WifiPsdu", logLevel);
+    LogComponentEnable("WifiRadioEnergyModel", logLevel);
+    LogComponentEnable("WifiRemoteStationManager", logLevel);
+    LogComponentEnable("WifiSpectrumPhyInterface", logLevel);
+    LogComponentEnable("WifiSpectrumSignalParameters", logLevel);
+    LogComponentEnable("WifiSpectrumValueHelper", logLevel);
+    LogComponentEnable("WifiTxCurrentModel", logLevel);
+    LogComponentEnable("WifiTxParameters", logLevel);
+    LogComponentEnable("WifiTxTimer", logLevel);
+    LogComponentEnable("YansErrorRateModel", logLevel);
+    LogComponentEnable("YansWifiChannel", logLevel);
+    LogComponentEnable("YansWifiPhy", logLevel);
 
-    LogComponentEnable("Athstats", LOG_LEVEL_ALL);
-    LogComponentEnable("WifiHelper", LOG_LEVEL_ALL);
-    LogComponentEnable("SpectrumWifiHelper", LOG_LEVEL_ALL);
-    LogComponentEnable("YansWifiHelper", LOG_LEVEL_ALL);
-
-    // From Spectrum
-    LogComponentEnable("WifiSpectrumValueHelper", LOG_LEVEL_ALL);
+    LogComponentEnable("Athstats", logLevel);
+    LogComponentEnable("WifiHelper", logLevel);
+    LogComponentEnable("SpectrumWifiHelper", logLevel);
+    LogComponentEnable("YansWifiHelper", logLevel);
 }
 
 int64_t
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-helper.h ns-3.42/src/wifi/helper/wifi-helper.h
--- ns-3.41/src/wifi/helper/wifi-helper.h	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/wifi-helper.h	2024-05-29 15:29:47.196073800 -0700
@@ -497,8 +497,9 @@
 
     /**
      * Helper to enable all WifiNetDevice log components with one statement
+     * \param logLevel (optional) log level setting
      */
-    static void EnableLogComponents();
+    static void EnableLogComponents(LogLevel logLevel = LOG_LEVEL_ALL);
 
     /**
      * Assign a fixed random variable stream number to the random variables
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-mac-helper.cc ns-3.42/src/wifi/helper/wifi-mac-helper.cc
--- ns-3.41/src/wifi/helper/wifi-mac-helper.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/wifi-mac-helper.cc	2024-05-29 15:29:47.196073800 -0700
@@ -22,14 +22,19 @@
 #include "ns3/boolean.h"
 #include "ns3/eht-configuration.h"
 #include "ns3/emlsr-manager.h"
+#include "ns3/enum.h"
 #include "ns3/frame-exchange-manager.h"
 #include "ns3/multi-user-scheduler.h"
+#include "ns3/pointer.h"
 #include "ns3/wifi-ack-manager.h"
 #include "ns3/wifi-assoc-manager.h"
 #include "ns3/wifi-mac-queue-scheduler.h"
 #include "ns3/wifi-net-device.h"
 #include "ns3/wifi-protection-manager.h"
 
+#include <sstream>
+#include <vector>
+
 namespace ns3
 {
 
@@ -38,6 +43,17 @@
     // By default, we create an AdHoc MAC layer (without QoS).
     SetType("ns3::AdhocWifiMac");
 
+    m_dcf.SetTypeId("ns3::Txop");
+    for (const auto& [aci, ac] : wifiAcList)
+    {
+        auto [it, inserted] = m_edca.try_emplace(aci);
+        it->second.SetTypeId("ns3::QosTxop");
+    }
+    m_channelAccessManager.SetTypeId("ns3::ChannelAccessManager");
+    // Setting FEM attributes requires setting a TypeId first. We initialize the TypeId to the FEM
+    // of the latest standard, in order to allow users to set the attributes of all the FEMs. The
+    // Create method will set the requested standard before creating the FEM(s).
+    m_frameExchangeManager.SetTypeId(GetFrameExchangeManagerTypeIdName(WIFI_STANDARD_COUNT, true));
     m_assocManager.SetTypeId("ns3::WifiDefaultAssocManager");
     m_queueScheduler.SetTypeId("ns3::FcfsWifiQueueScheduler");
     m_protectionManager.SetTypeId("ns3::WifiDefaultProtectionManager");
@@ -61,45 +77,69 @@
         macObjectFactory.Set("QosSupported", BooleanValue(true));
     }
 
+    // do not create a Txop if the standard is at least 802.11n
+    if (standard < WIFI_STANDARD_80211n)
+    {
+        auto dcf = m_dcf; // create a copy because this is a const method
+        dcf.Set("AcIndex", EnumValue<AcIndex>(AC_BE_NQOS));
+        macObjectFactory.Set("Txop", PointerValue(dcf.Create<Txop>()));
+    }
+    // create (Qos)Txop objects
+    for (auto [aci, edca] : m_edca)
+    {
+        edca.Set("AcIndex", EnumValue<AcIndex>(aci));
+        std::stringstream ss;
+        ss << aci << "_Txop";
+        auto s = ss.str().substr(3); // discard "AC "
+        macObjectFactory.Set(s, PointerValue(edca.Create<QosTxop>()));
+    }
+
+    // WaveNetDevice (through ns-3.38) stores PHY entities in a different member than WifiNetDevice,
+    // hence GetNPhys() would return 0
+    auto nLinks = std::max<uint8_t>(device->GetNPhys(), 1);
+
+    // create Channel Access Managers
+    std::vector<Ptr<ChannelAccessManager>> caManagers;
+    for (uint8_t linkId = 0; linkId < nLinks; ++linkId)
+    {
+        caManagers.emplace_back(m_channelAccessManager.Create<ChannelAccessManager>());
+    }
+
     Ptr<WifiMac> mac = macObjectFactory.Create<WifiMac>();
     mac->SetDevice(device);
     mac->SetAddress(Mac48Address::Allocate());
     device->SetMac(mac);
-    mac->ConfigureStandard(standard);
-
-    Ptr<WifiMacQueueScheduler> queueScheduler = m_queueScheduler.Create<WifiMacQueueScheduler>();
-    mac->SetMacQueueScheduler(queueScheduler);
+    mac->SetChannelAccessManagers(caManagers);
 
-    // WaveNetDevice (through ns-3.38) stores PHY entities in a different member than WifiNetDevice,
-    // hence GetNPhys() would return 0. We have to attach a protection manager and an ack manager to
-    // the unique instance of frame exchange manager anyway
-    for (uint8_t linkId = 0; linkId < std::max<uint8_t>(device->GetNPhys(), 1); ++linkId)
+    // create Frame Exchange Managers, each with an attached protection manager and ack manager
+    std::vector<Ptr<FrameExchangeManager>> feManagers;
+    auto frameExchangeManager = m_frameExchangeManager;
+    frameExchangeManager.SetTypeId(
+        GetFrameExchangeManagerTypeIdName(standard, mac->GetQosSupported()));
+    for (uint8_t linkId = 0; linkId < nLinks; ++linkId)
     {
-        auto fem = mac->GetFrameExchangeManager(linkId);
+        auto fem = frameExchangeManager.Create<FrameExchangeManager>();
+        feManagers.emplace_back(fem);
 
-        Ptr<WifiProtectionManager> protectionManager =
-            m_protectionManager.Create<WifiProtectionManager>();
+        auto protectionManager = m_protectionManager.Create<WifiProtectionManager>();
         protectionManager->SetWifiMac(mac);
         protectionManager->SetLinkId(linkId);
         fem->SetProtectionManager(protectionManager);
 
-        Ptr<WifiAckManager> ackManager = m_ackManager.Create<WifiAckManager>();
+        auto ackManager = m_ackManager.Create<WifiAckManager>();
         ackManager->SetWifiMac(mac);
         ackManager->SetLinkId(linkId);
         fem->SetAckManager(ackManager);
 
-        // 11be MLDs require a MAC address to be assigned to each STA. Note that
-        // FrameExchangeManager objects are created by WifiMac::SetupFrameExchangeManager
-        // (which is invoked by WifiMac::ConfigureStandard, which is called above),
-        // which sets the FrameExchangeManager's address to the address held by WifiMac.
-        // Hence, in case the number of PHY objects is 1, the FrameExchangeManager's
-        // address equals the WifiMac's address.
-        if (device->GetNPhys() > 1)
-        {
-            fem->SetAddress(Mac48Address::Allocate());
-        }
+        // 11be MLDs require a MAC address to be assigned to each STA
+        fem->SetAddress(device->GetNPhys() > 1 ? Mac48Address::Allocate() : mac->GetAddress());
     }
 
+    mac->SetFrameExchangeManagers(feManagers);
+
+    Ptr<WifiMacQueueScheduler> queueScheduler = m_queueScheduler.Create<WifiMacQueueScheduler>();
+    mac->SetMacQueueScheduler(queueScheduler);
+
     // create and install the Multi User Scheduler if this is an HE AP
     Ptr<ApWifiMac> apMac;
     if (standard >= WIFI_STANDARD_80211ax && m_muScheduler.IsTypeIdSet() &&
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-mac-helper.h ns-3.42/src/wifi/helper/wifi-mac-helper.h
--- ns-3.41/src/wifi/helper/wifi-mac-helper.h	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/wifi-mac-helper.h	2024-05-29 15:29:47.196073800 -0700
@@ -21,8 +21,11 @@
 #define WIFI_MAC_HELPER_H
 
 #include "ns3/object-factory.h"
+#include "ns3/qos-utils.h"
 #include "ns3/wifi-standards.h"
 
+#include <map>
+
 namespace ns3
 {
 
@@ -69,6 +72,43 @@
     void SetType(std::string type, Args&&... args);
 
     /**
+     * Helper function used to create and set the Txop object.
+     *
+     * \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
+     * \param args A sequence of name-value pairs of the attributes to set.
+     */
+    template <typename... Args>
+    void SetDcf(Args&&... args);
+
+    /**
+     * Helper function used to create and set the QosTxop object corresponding to the given AC.
+     *
+     * \param aci the AC index
+     * \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
+     * \param args A sequence of name-value pairs of the attributes to set.
+     */
+    template <typename... Args>
+    void SetEdca(AcIndex aci, Args&&... args);
+
+    /**
+     * Helper function used to set the Channel Access Manager object.
+     *
+     * \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
+     * \param args A sequence of name-value pairs of the attributes to set.
+     */
+    template <typename... Args>
+    void SetChannelAccessManager(Args&&... args);
+
+    /**
+     * Helper function used to set the Frame Exchange Manager object.
+     *
+     * \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
+     * \param args A sequence of name-value pairs of the attributes to set.
+     */
+    template <typename... Args>
+    void SetFrameExchangeManager(Args&&... args);
+
+    /**
      * Helper function used to set the Association Manager.
      *
      * \tparam Args \deduced Template type parameter pack for the sequence of name-value pairs.
@@ -139,13 +179,17 @@
     virtual Ptr<WifiMac> Create(Ptr<WifiNetDevice> device, WifiStandard standard) const;
 
   protected:
-    ObjectFactory m_mac;               ///< MAC object factory
-    ObjectFactory m_assocManager;      ///< Association Manager
-    ObjectFactory m_queueScheduler;    ///< MAC queue scheduler
-    ObjectFactory m_protectionManager; ///< Factory to create a protection manager
-    ObjectFactory m_ackManager;        ///< Factory to create an acknowledgment manager
-    ObjectFactory m_muScheduler;       ///< Multi-user Scheduler object factory
-    ObjectFactory m_emlsrManager;      ///< EMLSR Manager object factory
+    ObjectFactory m_mac;                                     ///< MAC object factory
+    ObjectFactory m_dcf;                                     ///< Txop (DCF) object factory
+    std::map<AcIndex, ObjectFactory, std::greater<>> m_edca; ///< QosTxop (EDCA) object factories
+    ObjectFactory m_channelAccessManager; ///< Channel Access Manager object factory
+    ObjectFactory m_frameExchangeManager; ///< Frame Exchange Manager object factory
+    ObjectFactory m_assocManager;         ///< Association Manager
+    ObjectFactory m_queueScheduler;       ///< MAC queue scheduler
+    ObjectFactory m_protectionManager;    ///< Factory to create a protection manager
+    ObjectFactory m_ackManager;           ///< Factory to create an acknowledgment manager
+    ObjectFactory m_muScheduler;          ///< Multi-user Scheduler object factory
+    ObjectFactory m_emlsrManager;         ///< EMLSR Manager object factory
 };
 
 } // namespace ns3
@@ -166,6 +210,36 @@
 }
 
 template <typename... Args>
+void
+WifiMacHelper::SetDcf(Args&&... args)
+{
+    m_dcf.Set(args...);
+}
+
+template <typename... Args>
+void
+WifiMacHelper::SetEdca(AcIndex aci, Args&&... args)
+{
+    auto it = m_edca.find(aci);
+    NS_ASSERT_MSG(it != m_edca.cend(), "No object factory for " << aci);
+    it->second.Set(args...);
+}
+
+template <typename... Args>
+void
+WifiMacHelper::SetChannelAccessManager(Args&&... args)
+{
+    m_channelAccessManager.Set(args...);
+}
+
+template <typename... Args>
+void
+WifiMacHelper::SetFrameExchangeManager(Args&&... args)
+{
+    m_frameExchangeManager.Set(args...);
+}
+
+template <typename... Args>
 void
 WifiMacHelper::SetAssocManager(std::string type, Args&&... args)
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-phy-rx-trace-helper.cc ns-3.42/src/wifi/helper/wifi-phy-rx-trace-helper.cc
--- ns-3.41/src/wifi/helper/wifi-phy-rx-trace-helper.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/helper/wifi-phy-rx-trace-helper.cc	2024-05-29 15:29:47.196073800 -0700
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (c) 2023 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "wifi-phy-rx-trace-helper.h"
+
+#include "ns3/boolean.h"
+#include "ns3/config.h"
+#include "ns3/fatal-error.h"
+#include "ns3/frame-exchange-manager.h"
+#include "ns3/log.h"
+#include "ns3/multi-model-spectrum-channel.h"
+#include "ns3/net-device-container.h"
+#include "ns3/node-container.h"
+#include "ns3/node-list.h"
+#include "ns3/pointer.h"
+#include "ns3/simulator.h"
+#include "ns3/spectrum-wifi-phy.h"
+#include "ns3/wifi-mac-header.h"
+#include "ns3/wifi-mac-queue.h"
+#include "ns3/wifi-mac.h"
+#include "ns3/wifi-mode.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/wifi-psdu.h"
+#include "ns3/wifi-spectrum-signal-parameters.h"
+#include "ns3/yans-wifi-phy.h"
+
+#include <algorithm>
+#include <iostream>
+#include <set>
+#include <string>
+#include <utility>
+
+namespace ns3
+{
+
+NS_LOG_COMPONENT_DEFINE("WifiPhyRxTraceHelper");
+
+/**
+ * Number of places to shift WifiPpdu UID values, when generating unique IDs
+ */
+const uint32_t SHIFT = 16;
+
+WifiPhyRxTraceHelper::WifiPhyRxTraceHelper()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+void
+WifiPhyRxTraceHelper::Enable(NodeContainer nodes)
+{
+    NS_LOG_FUNCTION(this << nodes.GetN());
+    Enable(nodes, MapMacAddressesToNodeIds(nodes));
+}
+
+void
+WifiPhyRxTraceHelper::Enable(NetDeviceContainer netDevices)
+{
+    NS_LOG_FUNCTION(this << netDevices.GetN());
+    NodeContainer nodes;
+    // filter netDevice entries through a set to prevent duplicate entries in the NodeContainer
+    std::set<Ptr<Node>> nodesSeen;
+    for (uint32_t i = 0; i < netDevices.GetN(); i++)
+    {
+        auto nodePtr = netDevices.Get(i)->GetNode();
+        if (nodesSeen.count(nodePtr) == 0)
+        {
+            nodesSeen.insert(nodePtr);
+            nodes.Add(nodePtr);
+        }
+    }
+    Enable(nodes, MapMacAddressesToNodeIds(nodes));
+}
+
+void
+WifiPhyRxTraceHelper::Enable(NodeContainer nodes,
+                             const std::map<Mac48Address, uint32_t>& macToNodeMap)
+{
+    NS_LOG_FUNCTION(this << nodes.GetN() << macToNodeMap.size());
+    NS_ABORT_MSG_IF(m_traceSink, "A trace sink is already configured for this helper");
+    m_traceSink = CreateObject<WifiPhyRxTraceSink>();
+    m_traceSink->SetMapMacAddressToNodeId(macToNodeMap);
+    for (uint32_t nodeId = 0; nodeId < nodes.GetN(); nodeId++)
+    {
+        for (uint32_t deviceId = 0; deviceId < nodes.Get(nodeId)->GetNDevices(); deviceId++)
+        {
+            auto wifiDevice = DynamicCast<WifiNetDevice>(nodes.Get(nodeId)->GetDevice(deviceId));
+            if (wifiDevice)
+            {
+                for (uint8_t i = 0; i < wifiDevice->GetNPhys(); i++)
+                {
+                    auto phy = wifiDevice->GetPhy(i);
+                    auto yansPhy = DynamicCast<YansWifiPhy>(phy);
+                    auto spectrumPhy = DynamicCast<SpectrumWifiPhy>(phy);
+                    NS_ASSERT_MSG(yansPhy || spectrumPhy, "Phy type not found");
+                    const std::string context =
+                        "/NodeList/" + std::to_string(wifiDevice->GetNode()->GetId()) +
+                        "/DeviceList/" + std::to_string(wifiDevice->GetIfIndex()) + "/Phys/" +
+                        std::to_string(i);
+                    auto connected = false;
+                    if (yansPhy)
+                    {
+                        connected = yansPhy->TraceConnect(
+                            "SignalArrival",
+                            context,
+                            MakeCallback(&WifiPhyRxTraceSink::PhySignalArrival, m_traceSink));
+                    }
+                    else if (spectrumPhy)
+                    {
+                        connected = spectrumPhy->TraceConnect(
+                            "SignalArrival",
+                            context,
+                            MakeCallback(&WifiPhyRxTraceSink::SpectrumPhySignalArrival,
+                                         m_traceSink));
+                    }
+                    else
+                    {
+                        NS_FATAL_ERROR("Phy type not found");
+                    }
+                    NS_ASSERT_MSG(connected, "Trace source not connected");
+                    connected = phy->TraceConnect(
+                        "SignalTransmission",
+                        context,
+                        MakeCallback(&WifiPhyRxTraceSink::PhySignalTransmission, m_traceSink));
+                    NS_ASSERT_MSG(connected, "Trace source not connected");
+                    // Log packet drops
+                    connected = phy->TraceConnect(
+                        "PhyRxPpduDrop",
+                        context,
+                        MakeCallback(&WifiPhyRxTraceSink::PhyPpduDrop, m_traceSink));
+                    NS_ASSERT_MSG(connected, "Trace source not connected");
+                    // Trace PHY Outcome events
+                    connected = phy->GetState()->TraceConnect(
+                        "RxOutcome",
+                        context,
+                        MakeCallback(&WifiPhyRxTraceSink::PpduOutcome, m_traceSink));
+                    NS_ASSERT_MSG(connected, "Trace source not connected");
+                }
+            }
+        }
+    }
+
+    // If a map is provided use map if not populate it yourself
+    if (!macToNodeMap.empty())
+    {
+        m_traceSink->SetMapMacAddressToNodeId(macToNodeMap);
+    }
+    // A linkID in one device might not be the same link on another device, need to create a mapping
+    // from node to link
+    m_traceSink->MapNodeToLinkToChannel(nodes);
+
+    if (!m_traceSink->IsCollectionPeriodActive())
+    {
+        NS_LOG_DEBUG("Connected traces but collection period is not active");
+    }
+}
+
+void
+WifiPhyRxTraceHelper::PrintStatistics() const
+{
+    m_traceSink->PrintStatistics();
+}
+
+void
+WifiPhyRxTraceHelper::PrintStatistics(Ptr<Node> node, uint32_t deviceId, uint8_t linkId) const
+{
+    m_traceSink->PrintStatistics(node->GetId(), deviceId, linkId);
+}
+
+void
+WifiPhyRxTraceHelper::PrintStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    m_traceSink->PrintStatistics(nodeId, deviceId, linkId);
+}
+
+void
+WifiPhyRxTraceHelper::Start(Time startTime)
+{
+    NS_LOG_FUNCTION(this << startTime.As(Time::S));
+    Simulator::Schedule(startTime, &WifiPhyRxTraceSink::Start, m_traceSink);
+}
+
+void
+WifiPhyRxTraceHelper::Stop(Time stopTime)
+{
+    NS_LOG_FUNCTION(this << stopTime.As(Time::S));
+    Simulator::Schedule(stopTime, &WifiPhyRxTraceSink::Stop, m_traceSink);
+}
+
+const std::vector<WifiPpduRxRecord>&
+WifiPhyRxTraceHelper::GetPpduRecords() const
+{
+    m_traceSink->CreateVectorFromRecords();
+    return m_traceSink->GetPpduRecords();
+}
+
+std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>>
+WifiPhyRxTraceHelper::GetPpduRecords(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    return m_traceSink->GetPpduRecords(nodeId, deviceId, linkId);
+}
+
+void
+WifiPhyRxTraceHelper::Reset()
+{
+    NS_LOG_FUNCTION(this);
+    NS_LOG_INFO("Reset WifiPhyRxTraceHelper");
+    m_traceSink->Reset();
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceHelper::GetStatistics() const
+{
+    return m_traceSink->GetStatistics();
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceHelper::GetStatistics(Ptr<Node> node, uint32_t deviceId, uint8_t linkId) const
+{
+    return m_traceSink->GetStatistics(node->GetId(), deviceId, linkId);
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceHelper::GetStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    return m_traceSink->GetStatistics(nodeId, deviceId, linkId);
+}
+
+std::map<Mac48Address, uint32_t>
+WifiPhyRxTraceHelper::MapMacAddressesToNodeIds(NodeContainer nodes) const
+{
+    std::map<Mac48Address, uint32_t> macAddressToNodeId;
+    for (uint32_t i = 0; i < nodes.GetN(); i++)
+    {
+        for (uint32_t device = 0; device < nodes.Get(i)->GetNDevices(); device++)
+        {
+            if (auto wdev = DynamicCast<WifiNetDevice>(nodes.Get(i)->GetDevice(device)))
+            {
+                for (uint32_t link = 0; link < wdev->GetNPhys(); link++)
+                {
+                    macAddressToNodeId[Mac48Address::ConvertFrom(
+                        wdev->GetMac()->GetFrameExchangeManager(link)->GetAddress())] =
+                        nodes.Get(i)->GetId();
+                    NS_LOG_DEBUG("NodeID: "
+                                 << nodes.Get(i)->GetId() << " DeviceID: " << device
+                                 << " LinkId: " << link << " MAC: "
+                                 << wdev->GetMac()->GetFrameExchangeManager(link)->GetAddress());
+                }
+            }
+        }
+    }
+    return macAddressToNodeId;
+}
+
+NS_OBJECT_ENSURE_REGISTERED(WifiPhyRxTraceSink);
+
+TypeId
+WifiPhyRxTraceSink::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::WifiPhyRxTraceSink")
+                            .SetParent<Object>()
+                            .SetGroupName("Wifi")
+                            .AddConstructor<WifiPhyRxTraceSink>();
+    return tid;
+}
+
+WifiPhyRxTraceSink::WifiPhyRxTraceSink()
+{
+    NS_LOG_FUNCTION(this);
+}
+
+void
+WifiPhyRxTraceSink::SetMapMacAddressToNodeId(
+    const std::map<Mac48Address, uint32_t>& MacAddressToNodeIdMap)
+{
+    m_macAddressToNodeId = MacAddressToNodeIdMap;
+}
+
+uint32_t
+WifiPhyRxTraceSink::ContextToNodeId(std::string context) const
+{
+    const auto sub = context.substr(10);
+    const auto pos = sub.find("/Device");
+    return std::stoi(sub.substr(0, pos));
+}
+
+int
+WifiPhyRxTraceSink::ContextToLinkId(std::string context) const
+{
+    const auto pos = context.find("/Phys/");
+    const auto sub = context.substr(pos + 6);
+    const auto nextSlashPos = sub.find('/');
+    if (nextSlashPos == std::string::npos)
+    {
+        return std::stoi(sub);
+    }
+    const auto physNumberStr = sub.substr(0, nextSlashPos);
+    return std::stoi(physNumberStr);
+}
+
+int
+WifiPhyRxTraceSink::ContextToDeviceId(std::string context) const
+{
+    auto pos = context.find("/DeviceList/");
+    pos += 12;
+    const auto sub = context.substr(pos);
+    const auto nextSlashPos = sub.find('/');
+    const auto deviceIdStr = sub.substr(0, nextSlashPos);
+    return std::stoi(deviceIdStr);
+}
+
+std::string
+WifiPhyRxTraceSink::ContextToTuple(std::string context) const
+{
+    const auto str = std::to_string(ContextToNodeId(context)) + ":" +
+                     std::to_string(ContextToDeviceId(context)) + ":" +
+                     std::to_string(ContextToLinkId(context));
+    return str;
+}
+
+// Each WifiPpdu has a UID, but more than one trace record can exist for a unique WifiPpdu
+// This generator shifts the WifiPpdu UID leftward and combines it with a member variable
+// counter to generate more than one unique ID for each WifiPpdu UID
+uint64_t
+WifiPhyRxTraceSink::UniqueTagGenerator::GenerateUniqueTag(uint64_t ppduUid)
+{
+    uint64_t tag;
+    do
+    {
+        tag = (ppduUid << SHIFT) | counter++;
+    } while (usedTags.find(tag) != usedTags.end());
+    usedTags.insert(tag);
+    NS_LOG_DEBUG("Generating tag " << tag << " from ppdu UID " << ppduUid);
+    return tag;
+}
+
+bool
+operator==(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs)
+{
+    return lhs.m_rxTag == rhs.m_rxTag;
+}
+
+bool
+operator!=(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs)
+{
+    return !(lhs == rhs);
+}
+
+bool
+operator<(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs)
+{
+    return lhs.m_rxTag < rhs.m_rxTag;
+}
+
+WifiPhyTraceStatistics
+operator+(const WifiPhyTraceStatistics& lhs, const WifiPhyTraceStatistics& rhs)
+{
+    WifiPhyTraceStatistics result;
+    result.m_overlappingPpdus = lhs.m_overlappingPpdus + rhs.m_overlappingPpdus;
+    result.m_nonOverlappingPpdus = lhs.m_nonOverlappingPpdus + rhs.m_nonOverlappingPpdus;
+    result.m_failedPpdus = lhs.m_failedPpdus + rhs.m_failedPpdus;
+    result.m_receivedPpdus = lhs.m_receivedPpdus + rhs.m_receivedPpdus;
+    result.m_receivedMpdus = lhs.m_receivedMpdus + rhs.m_receivedMpdus;
+    result.m_failedMpdus = lhs.m_failedMpdus + rhs.m_failedMpdus;
+
+    // Merge map fields
+    for (const auto& pair : lhs.m_ppduDropReasons)
+    {
+        result.m_ppduDropReasons[pair.first] += pair.second;
+    }
+    for (const auto& pair : rhs.m_ppduDropReasons)
+    {
+        result.m_ppduDropReasons[pair.first] += pair.second;
+    }
+    return result;
+}
+
+bool
+operator==(const WifiPhyTraceStatistics& lhs, const WifiPhyTraceStatistics& rhs)
+{
+    return lhs.m_overlappingPpdus == rhs.m_overlappingPpdus &&
+           lhs.m_nonOverlappingPpdus == rhs.m_nonOverlappingPpdus &&
+           lhs.m_failedPpdus == rhs.m_failedPpdus && lhs.m_receivedPpdus == rhs.m_receivedPpdus &&
+           lhs.m_receivedMpdus == rhs.m_receivedMpdus && lhs.m_failedMpdus == rhs.m_failedMpdus &&
+           lhs.m_ppduDropReasons == rhs.m_ppduDropReasons;
+}
+
+bool
+operator!=(const WifiPhyTraceStatistics& lhs, const WifiPhyTraceStatistics& rhs)
+{
+    return !(lhs == rhs);
+}
+
+void
+WifiPhyRxTraceSink::MapNodeToLinkToChannel(NodeContainer nodes)
+{
+    for (uint32_t i = 0; i < nodes.GetN(); i++)
+    {
+        for (uint32_t device = 0; device < nodes.Get(i)->GetNDevices(); device++)
+        {
+            auto wdev = DynamicCast<WifiNetDevice>(nodes.Get(i)->GetDevice(device));
+            if (wdev)
+            {
+                for (uint32_t link = 0; link < wdev->GetNPhys(); link++)
+                {
+                    m_nodeToDeviceToLinkToChannelInfo[nodes.Get(i)->GetId()][wdev->GetIfIndex()]
+                                                     [link] = std::make_pair(
+                                                         wdev->GetPhy(link)->GetChannelNumber(),
+                                                         wdev->GetPhy(link)->GetFrequency());
+
+                    NS_LOG_DEBUG("NodeId: "
+                                 << nodes.Get(i)->GetId() << " DeviceID: " << wdev->GetIfIndex()
+                                 << " LinkId: " << link
+                                 << " freq: " << wdev->GetPhy(link)->GetFrequency()
+                                 << " ch#: " << int(wdev->GetPhy(link)->GetChannelNumber()));
+                }
+            }
+        }
+    }
+}
+
+// channel number, frequency
+std::optional<std::pair<uint8_t, uint16_t>>
+WifiPhyRxTraceSink::GetChannelInfo(uint32_t nodeId, uint32_t deviceId, int link) const
+{
+    auto nodeIter = m_nodeToDeviceToLinkToChannelInfo.find(nodeId);
+    if (nodeIter != m_nodeToDeviceToLinkToChannelInfo.end())
+    {
+        auto& deviceMap = nodeIter->second;
+        auto deviceIter = deviceMap.find(deviceId);
+        if (deviceIter != deviceMap.end())
+        {
+            auto& linkMap = deviceIter->second;
+            auto linkIter = linkMap.find(link);
+            if (linkIter != linkMap.end())
+            {
+                return std::optional<std::pair<uint8_t, uint16_t>>(linkIter->second);
+            }
+        }
+    }
+    return std::nullopt;
+}
+
+// TODO: Profile this and possibly refactor to avoid duplicates
+void
+WifiPhyRxTraceSink::UpdateCurrentlyReceivedSignal(uint32_t nodeId,
+                                                  uint32_t deviceId,
+                                                  uint8_t linkId)
+{
+    NS_LOG_FUNCTION(this << nodeId << deviceId << linkId);
+    // Add all overlapping packets to the list of overlapping packets for this frame arrival
+    for (const auto& it : m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(linkId))
+    {
+        for (const auto& iter : m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(linkId))
+        {
+            if (it != iter)
+            {
+                m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].emplace_back(iter);
+            }
+        }
+    }
+
+    // Remove duplicates
+    for (const auto& it : m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(linkId))
+    {
+        // First, sort the vector to bring duplicates together
+        std::sort(m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].begin(),
+                  m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].end());
+        // Use std::unique to remove duplicates (adjacent identical elements)
+        m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].erase(
+            std::unique(m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].begin(),
+                        m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].end()),
+            m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].end());
+    }
+    NS_LOG_INFO(
+        "Map of overlapping PPDU records size: " << m_rxTagToListOfOverlappingPpduRecords.size());
+}
+
+void
+WifiPhyRxTraceSink::EndTx(uint32_t nodeId, uint32_t deviceId, WifiPpduRxRecord ppduRecord)
+{
+    NS_LOG_FUNCTION(this << nodeId << deviceId);
+    // remove from currently received (in this case transmitted) packets
+    NS_LOG_INFO("Remove transmit record at " << nodeId << ":" << deviceId << ":"
+                                             << +ppduRecord.m_linkId << " UID "
+                                             << ppduRecord.m_rxTag);
+    m_nodeDeviceLinkRxRecords.at(nodeId)
+        .at(deviceId)
+        .at(ppduRecord.m_linkId)
+        .erase(
+            std::remove(
+                m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).begin(),
+                m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end(),
+                ppduRecord),
+            m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end());
+    NS_LOG_INFO("Size of m_nodeDeviceLinkRxRecords: " << m_nodeDeviceLinkRxRecords.size());
+
+    // Erase the item from rxTagToPpduRecord
+    m_rxTagToPpduRecord.erase(ppduRecord.m_rxTag);
+    NS_LOG_INFO("Size of m_rxTagToPpduRecord: " << m_rxTagToPpduRecord.size());
+}
+
+void
+WifiPhyRxTraceSink::PhyRxEnd(uint32_t nodeId, uint32_t deviceId, uint64_t rxTag, uint64_t ppduUid)
+{
+    NS_LOG_FUNCTION(this << nodeId << deviceId << rxTag << ppduUid);
+    NS_ASSERT_MSG(m_rxTagToPpduRecord.contains(rxTag), "Missing PPDU at PhyRxEnd");
+    // Update the end time on the record, and reinsert to the map
+    auto ppduRecord = m_rxTagToPpduRecord[rxTag];
+    ppduRecord.m_endTime = Simulator::Now();
+    auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(rxTag, ppduRecord);
+    NS_ASSERT_MSG(!inserted, "Did not assign successfully");
+
+    // Update the lists of overlapping PPDUs
+    UpdateCurrentlyReceivedSignal(nodeId, deviceId, ppduRecord.m_linkId);
+    for (const auto& it : m_rxTagToListOfOverlappingPpduRecords[rxTag])
+    {
+        ppduRecord.m_overlappingPpdu.emplace_back(it);
+    }
+
+    NS_LOG_INFO("Remove reception record at " << nodeId << ":" << deviceId << ":"
+                                              << +ppduRecord.m_linkId << " UID " << rxTag);
+    // Remove from map of active records
+    m_nodeDeviceLinkRxRecords.at(nodeId)
+        .at(deviceId)
+        .at(ppduRecord.m_linkId)
+        .erase(
+            std::remove(
+                m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).begin(),
+                m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end(),
+                ppduRecord),
+            m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end());
+    NS_LOG_INFO("Size of m_nodeDeviceLinkRxRecords: " << m_nodeDeviceLinkRxRecords.size());
+
+    // Erase the item from rxTagToPpduRecord
+    m_rxTagToPpduRecord.erase(rxTag);
+    NS_LOG_INFO("Size of m_rxTagToPpduRecord: " << m_rxTagToPpduRecord.size());
+
+    // checks if statistics period has been started before adding to the list of completed records
+    if (m_statisticsCollectionPeriodStarted)
+    {
+        NS_LOG_INFO("Adding PPDU record for " << ppduRecord.m_receiverId << " " << deviceId << " "
+                                              << +ppduRecord.m_linkId);
+        m_completedRecords[ppduRecord.m_receiverId][deviceId][ppduRecord.m_linkId].emplace_back(
+            ppduRecord);
+    }
+    else
+    {
+        NS_LOG_DEBUG("Not adding PPDU record (statistics not started) for "
+                     << ppduRecord.m_receiverId << " " << deviceId << " " << ppduRecord.m_linkId);
+    }
+}
+
+bool
+WifiPhyRxTraceSink::IsCollectionPeriodActive() const
+{
+    return m_statisticsCollectionPeriodStarted;
+}
+
+void
+WifiPhyRxTraceSink::Start()
+{
+    m_statisticsCollectionPeriodStarted = true;
+}
+
+void
+WifiPhyRxTraceSink::Stop()
+{
+    m_statisticsCollectionPeriodStarted = false;
+}
+
+void
+WifiPhyRxTraceSink::PhySignalTransmission(std::string context,
+                                          Ptr<const WifiPpdu> ppdu,
+                                          const WifiTxVector& txVector)
+{
+    NS_LOG_FUNCTION(context << ppdu << txVector);
+    uint32_t nodeId = ContextToNodeId(context);
+    uint32_t deviceId = ContextToDeviceId(context);
+    uint8_t linkId = ContextToLinkId(context);
+
+    WifiPpduRxRecord ppduRecord;
+    ppduRecord.m_startTime = Simulator::Now();
+    ppduRecord.m_endTime = Simulator::Now() + ppdu->GetTxDuration();
+    ppduRecord.m_ppdu = ppdu;
+    ppduRecord.m_senderId = nodeId;
+    ppduRecord.m_linkId = linkId;
+    ppduRecord.m_senderDeviceId = deviceId;
+
+    // Tag used to determine which packet needs to be removed from currently received packets
+    ppduRecord.m_rxTag = m_tagGenerator.GenerateUniqueTag(ppdu->GetUid());
+
+    NS_LOG_INFO("Transmit at " << ContextToTuple(context) << " insert to tagToRecord map for UID "
+                               << ppduRecord.m_rxTag);
+    auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(ppduRecord.m_rxTag, ppduRecord);
+    NS_ASSERT_MSG(inserted, "Did not insert successfully");
+    NS_LOG_INFO("Size of m_rxTagToPpduRecord: " << m_rxTagToPpduRecord.size());
+
+    /*
+        m_rxTagToPpduRecord[ppduRecord.m_rxTag] = ppduRecord;
+    */
+
+    // Use this to find who is the sender in the reception side
+    m_ppduUidToTxTag[ppduRecord.m_ppdu->GetUid()] = ppduRecord.m_rxTag;
+
+    // store record in a map, indexed by nodeId, deviceId, linkId
+    NS_LOG_INFO("Transmit at " << ContextToTuple(context)
+                               << " insert to active records map for UID " << ppduRecord.m_rxTag);
+    m_nodeDeviceLinkRxRecords[nodeId][deviceId][linkId].emplace_back(ppduRecord);
+    NS_LOG_INFO("Size of active records: " << m_nodeDeviceLinkRxRecords.size());
+
+    Simulator::Schedule(ppduRecord.m_endTime - ppduRecord.m_startTime,
+                        &WifiPhyRxTraceSink::EndTx,
+                        this,
+                        nodeId,
+                        deviceId,
+                        ppduRecord);
+}
+
+void
+WifiPhyRxTraceSink::SpectrumPhySignalArrival(std::string context,
+                                             Ptr<const SpectrumSignalParameters> signal,
+                                             uint32_t senderNodeId,
+                                             double rxPower,
+                                             Time duration)
+{
+    NS_LOG_FUNCTION(context << signal << senderNodeId << rxPower << duration);
+    const auto wifiSignal = DynamicCast<const WifiSpectrumSignalParameters>(signal);
+    const auto ppdu = wifiSignal->ppdu;
+
+    if (!wifiSignal)
+    {
+        NS_LOG_DEBUG("Non-WiFi Signal Received");
+        return;
+    }
+    PhySignalArrival(context, ppdu, rxPower, duration);
+}
+
+void
+WifiPhyRxTraceSink::PhySignalArrival(std::string context,
+                                     Ptr<const WifiPpdu> ppdu,
+                                     double rxPower,
+                                     Time duration)
+{
+    NS_LOG_FUNCTION(context << ppdu << rxPower << duration);
+    uint32_t nodeId = ContextToNodeId(context);
+    uint32_t deviceId = ContextToDeviceId(context);
+    uint8_t linkId = ContextToLinkId(context);
+
+    // Associate this received PPDU with a record previously stored on the transmit side, if present
+    bool hasTxTag = false;
+    WifiPpduRxRecord txPpduRecord;
+    if (m_ppduUidToTxTag.contains(ppdu->GetUid()))
+    {
+        hasTxTag = true;
+        txPpduRecord = m_rxTagToPpduRecord[m_ppduUidToTxTag[ppdu->GetUid()]];
+        NS_LOG_DEBUG("Arrival RxNodeID: " << nodeId << " SenderID: " << txPpduRecord.m_senderId
+                                          << " Received on LinkID: " << +linkId
+                                          << " Frame Sent on LinkId: " << +txPpduRecord.m_linkId);
+    }
+    else
+    {
+        NS_LOG_DEBUG("Arrival RxNodeID: " << nodeId << " Received on LinkID: " << +linkId
+                                          << "; no sender info");
+    }
+    if (hasTxTag)
+    {
+        auto rxInfo = GetChannelInfo(nodeId, deviceId, linkId);
+        auto txInfo = GetChannelInfo(txPpduRecord.m_senderId,
+                                     txPpduRecord.m_senderDeviceId,
+                                     txPpduRecord.m_linkId);
+        if (!txInfo.has_value())
+        {
+            NS_LOG_DEBUG(
+                "Didn't find TX record for transmission; possibly from an untraced sender");
+        }
+        else
+        {
+            if ((int(txInfo->second) != int(rxInfo->second)) ||
+                (int(txInfo->first) != int(rxInfo->first)))
+            {
+                NS_LOG_DEBUG(
+                    "Received Signal on a different frequency or channel number than what was "
+                    "configured for this PHY or link");
+                return;
+            }
+        }
+    }
+
+    WifiPpduRxRecord ppduRecord;
+    ppduRecord.m_startTime = Simulator::Now();
+    ppduRecord.m_endTime = Simulator::Now() + duration;
+    ppduRecord.m_ppdu = ppdu;
+    ppduRecord.m_rssi = rxPower;
+    ppduRecord.m_rxTag = m_tagGenerator.GenerateUniqueTag(ppdu->GetUid());
+    ppduRecord.m_receiverId = nodeId;
+    ppduRecord.m_linkId = linkId;
+    if (hasTxTag)
+    {
+        ppduRecord.m_senderId = txPpduRecord.m_senderId;
+        ppduRecord.m_senderDeviceId = txPpduRecord.m_senderDeviceId;
+        NS_LOG_INFO(
+            "Receive at " << ContextToTuple(context) << " from node " << txPpduRecord.m_senderId
+                          << "; insert to active records map for UID " << ppduRecord.m_rxTag);
+    }
+    else
+    {
+        NS_LOG_INFO("Receive at " << ContextToTuple(context)
+                                  << "; insert to active records map for UID "
+                                  << ppduRecord.m_rxTag);
+    }
+
+    // Add to list of currently received frames on this node, device and specific link
+    m_nodeDeviceLinkRxRecords[nodeId][deviceId][linkId].emplace_back(ppduRecord);
+    NS_LOG_INFO("Size of active records " << m_nodeDeviceLinkRxRecords.size());
+
+    UpdateCurrentlyReceivedSignal(nodeId, deviceId, linkId);
+
+    NS_LOG_INFO("Receive at " << ContextToTuple(context) << " insert to tagToRecord map for UID "
+                              << ppduRecord.m_rxTag);
+    auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(ppduRecord.m_rxTag, ppduRecord);
+    NS_ASSERT_MSG(inserted, "Did not insert successfully");
+    NS_LOG_INFO("Size of m_rxTagToPpduRecord " << m_rxTagToPpduRecord.size());
+
+    NS_LOG_INFO("Receive at " << ContextToTuple(context) << " insert to highly nested map for UID "
+                              << ppduRecord.m_rxTag);
+    m_nodeDeviceLinkPidToRxId[nodeId][deviceId][linkId][ppduRecord.m_ppdu->GetUid()] =
+        ppduRecord.m_rxTag;
+    NS_LOG_INFO("Size of highly nested map " << m_nodeDeviceLinkPidToRxId.size());
+}
+
+void
+WifiPhyRxTraceSink::PhyPpduDrop(std::string context,
+                                Ptr<const WifiPpdu> ppdu,
+                                WifiPhyRxfailureReason reason)
+{
+    NS_LOG_FUNCTION(this << context << ppdu << reason);
+    uint32_t nodeId = ContextToNodeId(context);
+    uint32_t deviceId = ContextToDeviceId(context);
+    uint8_t linkId = ContextToLinkId(context);
+    WifiPpduRxRecord ppduRecord =
+        m_rxTagToPpduRecord[m_nodeDeviceLinkPidToRxId[nodeId][deviceId][linkId][ppdu->GetUid()]];
+
+    if (ppduRecord.m_ppdu == nullptr)
+    {
+        NS_LOG_DEBUG("Frame being dropped was not observed on SignalArrival trace. Means it was "
+                     "received on a wrong link configuration");
+        return;
+    }
+    ppduRecord.m_reason = reason;
+
+    std::vector<bool> outcome;
+    for (const auto& mpdu : *PeekPointer(ppdu->GetPsdu()))
+    {
+        mpdu->GetPacket();
+        outcome.emplace_back(false);
+    }
+    ppduRecord.m_statusPerMpdu = outcome;
+    m_rxTagToPpduRecord[ppduRecord.m_rxTag] = ppduRecord;
+
+    Simulator::Schedule(ppduRecord.m_endTime - Simulator::Now(),
+                        &WifiPhyRxTraceSink::PhyRxEnd,
+                        this,
+                        nodeId,
+                        deviceId,
+                        ppduRecord.m_rxTag,
+                        ppdu->GetUid());
+}
+
+void
+WifiPhyRxTraceSink::PpduOutcome(std::string context,
+                                Ptr<const WifiPpdu> ppdu,
+                                RxSignalInfo signal,
+                                const WifiTxVector& txVector,
+                                const std::vector<bool>& statusMpdu)
+{
+    NS_LOG_FUNCTION(context << ppdu << signal << txVector);
+    uint32_t nodeId = ContextToNodeId(context);
+    uint32_t deviceId = ContextToDeviceId(context);
+    uint8_t linkId = ContextToLinkId(context);
+
+    WifiPpduRxRecord ppduRecord =
+        m_rxTagToPpduRecord[m_nodeDeviceLinkPidToRxId[nodeId][deviceId][linkId][ppdu->GetUid()]];
+
+    if (ppduRecord.m_ppdu)
+    {
+        NS_LOG_DEBUG("Found an expected frame in the outcome");
+    }
+    else
+    {
+        NS_LOG_DEBUG("Frame to be processed was not observed on SignalArrival trace");
+        return;
+    }
+    // Save the reception status per MPDU in the PPDU record
+    ppduRecord.m_statusPerMpdu = statusMpdu;
+
+    auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(ppduRecord.m_rxTag, ppduRecord);
+    NS_ASSERT_MSG(!inserted, "Did not assign successfully");
+    PhyRxEnd(nodeId, deviceId, ppduRecord.m_rxTag, ppdu->GetUid());
+}
+
+void
+WifiPhyRxTraceSink::CountStatisticsForRecord(WifiPhyTraceStatistics& statistics,
+                                             const WifiPpduRxRecord& record) const
+{
+    // Check if PPDU was dropped and if any MPDU was addressed to the receiver
+    if (record.m_reason)
+    {
+        bool mpduToReceiver = false;
+        bool shouldCount = true;
+        Ptr<const Packet> p;
+        auto it = record.m_statusPerMpdu.begin();
+        for (const auto& mpdu : *PeekPointer(record.m_ppdu->GetPsdu()))
+        {
+            p = mpdu->GetProtocolDataUnit();
+            WifiMacHeader hdr;
+            p->PeekHeader(hdr);
+            if (!(hdr.IsData() &&
+                  (hdr.GetType() == WIFI_MAC_DATA || hdr.GetType() == WIFI_MAC_QOSDATA)))
+            {
+                shouldCount = false;
+                break;
+            }
+            if (!(*it) && (record.m_receiverId == m_macAddressToNodeId.at(hdr.GetAddr1())))
+            {
+                // Failed MPDU
+                statistics.m_failedMpdus++;
+                mpduToReceiver = true;
+            }
+            ++it;
+        }
+        // At least one MPDU addressed to the receiver was dropped, mark PPDU as
+        // failed
+        if (mpduToReceiver && shouldCount)
+        {
+            statistics.m_failedPpdus++;
+            // Check if PPDU Overlap
+            if (!record.m_overlappingPpdu.empty())
+            {
+                // Yes Overlap
+                statistics.m_overlappingPpdus++;
+            }
+            else
+            {
+                // No Overlap
+                statistics.m_nonOverlappingPpdus++;
+            }
+            // It is due to a drop, clarify and count the reason
+            statistics.m_ppduDropReasons[record.m_reason]++;
+        }
+    }
+    else
+    {
+        // Payload Decode Attempt (No Drop but still not certain of MPDU outcome)
+        // MPDU Level
+
+        Ptr<const Packet> p;
+        auto it = record.m_statusPerMpdu.begin();
+        bool mpduFail = false;
+        bool shouldCount = true;
+        bool mpduToReceiver = false;
+        for (const auto& mpdu : *PeekPointer(record.m_ppdu->GetPsdu()))
+        {
+            p = mpdu->GetProtocolDataUnit();
+            WifiMacHeader hdr;
+            p->PeekHeader(hdr);
+            if (!(hdr.IsData() &&
+                  (hdr.GetType() == WIFI_MAC_DATA || hdr.GetType() == WIFI_MAC_QOSDATA)))
+            {
+                shouldCount = false;
+                break;
+            }
+            if (*it && (m_macAddressToNodeId.contains(hdr.GetAddr1())) &&
+                (record.m_receiverId == m_macAddressToNodeId.at(hdr.GetAddr1())))
+            {
+                // Successful MPDU
+                statistics.m_receivedMpdus++;
+                mpduToReceiver = true;
+            }
+            else if (!(*it) && (m_macAddressToNodeId.contains(hdr.GetAddr1())) &&
+                     (record.m_receiverId == m_macAddressToNodeId.at(hdr.GetAddr1())))
+            {
+                // Failed MPDU
+                statistics.m_failedMpdus++;
+                mpduFail = true;
+                mpduToReceiver = true;
+            }
+            ++it;
+        }
+        if (!mpduFail && shouldCount && mpduToReceiver)
+        {
+            // No drops or payload decode errors for all MPDUs addressed to the
+            // receiver
+            statistics.m_receivedPpdus++;
+
+            // Check if PPDU Overlap
+            if (!record.m_overlappingPpdu.empty())
+            {
+                // Yes Overlap
+                statistics.m_overlappingPpdus++;
+            }
+            else
+            {
+                // No Overlap
+                statistics.m_nonOverlappingPpdus++;
+            }
+        }
+        else if (shouldCount && mpduToReceiver)
+        {
+            // At least one MPDU addressed to the receiver failed.
+            statistics.m_failedPpdus++;
+            // Check if PPDU Overlap
+            if (!record.m_overlappingPpdu.empty())
+            {
+                // Yes Overlap
+                statistics.m_overlappingPpdus++;
+            }
+            else
+            {
+                // No Overlap
+                statistics.m_nonOverlappingPpdus++;
+            }
+        }
+    }
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceSink::CountStatistics() const
+{
+    NS_LOG_FUNCTION(this);
+    WifiPhyTraceStatistics statistics;
+    for (const auto& nodeMap : m_completedRecords)
+    {
+        for (const auto& deviceMap : nodeMap.second)
+        {
+            for (const auto& linkMap : deviceMap.second)
+            {
+                for (const auto& record : linkMap.second)
+                {
+                    CountStatisticsForRecord(statistics, record);
+                }
+            }
+        }
+    }
+    return statistics;
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceSink::CountStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    NS_LOG_FUNCTION(this << nodeId << deviceId << linkId);
+    WifiPhyTraceStatistics statistics;
+    if (m_completedRecords.contains(nodeId))
+    {
+        auto mapOfDevices = m_completedRecords.at(nodeId);
+        if (mapOfDevices.contains(deviceId))
+        {
+            auto mapOfLinks = mapOfDevices.at(deviceId);
+            if (mapOfLinks.contains(linkId))
+            {
+                auto vectorOfRecords = mapOfLinks.at(linkId);
+                for (const auto& record : vectorOfRecords)
+                {
+                    CountStatisticsForRecord(statistics, record);
+                }
+            }
+        }
+    }
+    return statistics;
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceSink::GetStatistics() const
+{
+    WifiPhyTraceStatistics stats = CountStatistics();
+    return stats;
+}
+
+WifiPhyTraceStatistics
+WifiPhyRxTraceSink::GetStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    WifiPhyTraceStatistics stats = CountStatistics(nodeId, deviceId, linkId);
+    return stats;
+}
+
+void
+WifiPhyRxTraceSink::PrintStatistics() const
+{
+    WifiPhyTraceStatistics statistics = CountStatistics();
+
+    std::cout << "Total PPDUs Received: " << statistics.m_receivedPpdus + statistics.m_failedPpdus
+              << std::endl;
+    std::cout << "Total Non-Overlapping PPDUs Received: " << statistics.m_nonOverlappingPpdus
+              << std::endl;
+    std::cout << "Total Overlapping PPDUs Received: " << statistics.m_overlappingPpdus << std::endl;
+
+    std::cout << "\nSuccessful PPDUs: " << statistics.m_receivedPpdus << std::endl;
+    std::cout << "Failed PPDUs: " << statistics.m_failedPpdus << std::endl;
+    for (auto reason : statistics.m_ppduDropReasons)
+    {
+        std::cout << "PPDU Dropped due to " << reason.first << ": " << reason.second << std::endl;
+    }
+    std::cout << "\nTotal MPDUs: " << statistics.m_failedMpdus + statistics.m_receivedMpdus
+              << std::endl;
+    std::cout << "Total Successful MPDUs: " << statistics.m_receivedMpdus << std::endl;
+    std::cout << "Total Failed MPDUs: " << statistics.m_failedMpdus << std::endl;
+}
+
+void
+WifiPhyRxTraceSink::PrintStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    WifiPhyTraceStatistics statistics = CountStatistics(nodeId, deviceId, linkId);
+    std::cout << "Total PPDUs Received: " << statistics.m_receivedPpdus + statistics.m_failedPpdus
+              << std::endl;
+    std::cout << "Total Non-Overlapping PPDUs Received: " << statistics.m_nonOverlappingPpdus
+              << std::endl;
+    std::cout << "Total Overlapping PPDUs Received: " << statistics.m_overlappingPpdus << std::endl;
+
+    std::cout << "\nSuccessful PPDUs: " << statistics.m_receivedPpdus << std::endl;
+    std::cout << "Failed PPDUs: " << statistics.m_failedPpdus << std::endl;
+    for (auto reason : statistics.m_ppduDropReasons)
+    {
+        std::cout << "PPDU Dropped due to " << reason.first << ": " << reason.second << std::endl;
+    }
+    std::cout << "\nTotal MPDUs: " << statistics.m_failedMpdus + statistics.m_receivedMpdus
+              << std::endl;
+    std::cout << "Total Successful MPDUs: " << statistics.m_receivedMpdus << std::endl;
+    std::cout << "Total Failed MPDUs: " << statistics.m_failedMpdus << std::endl;
+}
+
+void
+WifiPhyRxTraceSink::Reset()
+{
+    m_completedRecords.clear();
+    m_records.clear();
+}
+
+// Return a single vector with all completed records
+void
+WifiPhyRxTraceSink::CreateVectorFromRecords()
+{
+    m_records.clear();
+    for (const auto& nodeMap : m_completedRecords)
+    {
+        for (const auto& deviceMap : nodeMap.second)
+        {
+            for (const auto& linkMap : deviceMap.second)
+            {
+                for (const auto& wifiRecord : linkMap.second)
+                {
+                    m_records.emplace_back(wifiRecord);
+                }
+            }
+        }
+    }
+}
+
+const std::vector<WifiPpduRxRecord>&
+WifiPhyRxTraceSink::GetPpduRecords() const
+{
+    return m_records;
+}
+
+std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>>
+WifiPhyRxTraceSink::GetPpduRecords(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
+{
+    if (m_completedRecords.contains(nodeId))
+    {
+        if (m_completedRecords.at(nodeId).contains(deviceId))
+        {
+            if (m_completedRecords.at(nodeId).at(deviceId).contains(linkId))
+            {
+                return std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>>(
+                    m_completedRecords.at(nodeId).at(deviceId).at(linkId));
+            }
+        }
+    }
+    return std::nullopt;
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-phy-rx-trace-helper.h ns-3.42/src/wifi/helper/wifi-phy-rx-trace-helper.h
--- ns-3.41/src/wifi/helper/wifi-phy-rx-trace-helper.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/helper/wifi-phy-rx-trace-helper.h	2024-05-29 15:29:47.196073800 -0700
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2023 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef WIFI_PHY_RX_TRACE_HELPER_H
+#define WIFI_PHY_RX_TRACE_HELPER_H
+
+#include "ns3/nstime.h"
+#include "ns3/object.h"
+#include "ns3/phy-entity.h"
+#include "ns3/ptr.h"
+#include "ns3/wifi-phy-common.h"
+#include "ns3/wifi-phy-state.h"
+#include "ns3/wifi-ppdu.h"
+
+#include <functional>
+#include <map>
+#include <optional>
+#include <set>
+#include <string>
+#include <vector>
+
+// Forward declare some friend test classes that access private methods
+class TestWifiPhyRxTraceHelper;
+class TestWifiPhyRxTraceHelperMloStr;
+class TestWifiPhyRxTraceHelperYans;
+
+namespace ns3
+{
+
+class Mac48Address;
+class NetDeviceContainer;
+class Node;
+class NodeContainer;
+struct SpectrumSignalParameters;
+class WifiPhyRxTraceSink;
+class WifiTxVector;
+
+/**
+ * @struct WifiPhyTraceStatistics
+ * @brief Keeps track of PHY layer trace statistics.
+ *
+ * This structure stores various statistics related to the Physical Layer (PHY) of the Wi-Fi
+ * communication, including the number of successful and failed PPDUs containing unicast data,
+ * and unicast data MPDU receptions.
+ */
+struct WifiPhyTraceStatistics
+{
+    uint64_t m_overlappingPpdus{
+        0}; ///< Number of PPDUs that overlapped in time with at least one other PPDU.
+    uint64_t m_nonOverlappingPpdus{
+        0}; ///< Number of PPDUs that did not overlap in time with any other PPDU.
+    uint64_t m_receivedPpdus{0}; ///< Number of successfully received PPDUs (with unicast data).
+    uint64_t m_failedPpdus{0};   ///< Number of failed PPDU receptions (with unicast data).
+    uint64_t m_receivedMpdus{0}; ///< Number of successfully received unicast data MPDUs.
+    uint64_t m_failedMpdus{0};   ///< Number of failed unicast data MPDU receptions.
+    std::map<WifiPhyRxfailureReason, uint64_t> m_ppduDropReasons; ///< Counts of the drop reasons
+};
+
+/**
+ * @struct WifiPpduRxRecord
+ * @brief Structure recording a received PPDU (Physical Protocol Data Unit) in a Wi-Fi network.
+ *
+ * This structure contains various details about the received PPDU, such as signal strength,
+ * identifiers for the sender and receiver, timing information, and reception status.
+ */
+struct WifiPpduRxRecord
+{
+    Ptr<const WifiPpdu> m_ppdu{nullptr}; ///< Pointer to the received PPDU.
+    double m_rssi{0};                    ///< Received Signal Strength Indicator (RSSI) in dBm.
+    uint64_t m_rxTag{
+        std::numeric_limits<uint64_t>::max()}; ///< Unique tag for the reception of this PPDU.
+    uint32_t m_receiverId{std::numeric_limits<uint32_t>::max()}; ///< Node ID of the receiver.
+    Time m_startTime; ///< Start time of the PPDU reception.
+    Time m_endTime;   ///< End time of the PPDU reception.
+    WifiPhyRxfailureReason m_reason{
+        WifiPhyRxfailureReason::UNKNOWN}; ///< Reason for reception failure, if any.
+    std::vector<WifiPpduRxRecord>
+        m_overlappingPpdu; ///< List of PPDUs that overlapped in time with this reception.
+    std::vector<bool> m_statusPerMpdu; ///< Reception status for each MPDU within the PPDU.
+    uint8_t m_linkId{std::numeric_limits<uint8_t>::max()}; ///< The link ID belonging to this record
+    uint32_t m_senderId{std::numeric_limits<uint32_t>::max()};       ///< Node ID of the sender.
+    uint32_t m_senderDeviceId{std::numeric_limits<uint32_t>::max()}; ///< Device ID of Sender
+};
+
+/**
+ * @class WifiPhyRxTraceHelper
+ * @brief Assists in tracing and analyzing Wi-Fi Physical Layer (PHY) receptions.
+ *
+ * The WifiPhyRxTraceHelper class can be used to instrument Wi-Fi nodes (or devices, or
+ * links) to keep track of the reception of Wi-Fi signals, and in particular, whether they overlap
+ * (collide) with one another.  The implementation maintains reception records within internal
+ * data structures, and statistics or full reception records can be queried.
+ *
+ * The class provides functionality to connect traces to all nodes and WifiNetDevices within scope,
+ * enabling the capture of all Physical Protocol Data Units (PPDUs) received. It also
+ * allows for the collection and retrieval of statistics related to successful and failed receptions
+ * of PPDUs containing unicast data, and their corresponding MAC Protocol Data Units (MPDUs).
+ *
+ * Key features include:
+ * - Enabling trace connections to capture reception data.
+ * - Starting and stopping the collection of statistics at specified times.
+ * - Resetting the collected data for fresh starts in data collection.
+ * - Accessing detailed reception records for further analysis.
+ *
+ * Usage involves connecting to desired nodes or devices, (optionally) managing the
+ * collection period with start, stop, and reset methods, and finally, accessing the collected
+ * statistics or reception records.
+ *
+ * Statistics are only compiled for unicast data (WIFI_MAC_DATA and WIFI_MAC_QOSDATA), although
+ * PPDU records are kept for all frame types because it is possible for non-data frames to
+ * collide with data frames.
+ */
+class WifiPhyRxTraceHelper
+{
+    friend class ::TestWifiPhyRxTraceHelper;
+    friend class ::TestWifiPhyRxTraceHelperMloStr;
+    friend class ::TestWifiPhyRxTraceHelperYans;
+
+  public:
+    /**
+     * Constructor.
+     */
+    WifiPhyRxTraceHelper();
+
+    /**
+     * Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
+     * @param nodes The NodeContainer to which traces are to be connected.
+     */
+    void Enable(NodeContainer nodes);
+
+    /**
+     * Enables trace collection for all nodes corresponding to the devices in the specified
+     * NetDeviceContainer.
+     * @param devices The NetDeviceContainer containing nodes to which traces are to be connected.
+     */
+    void Enable(NetDeviceContainer devices);
+
+    /**
+     * Retrieves current statistics of successful and failed data PPDUs and MPDUs receptions,
+     * for all nodes, devices, and links that have been enabled.
+     *
+     * Statistics are compiled for the current observation window, which extends to the
+     * trace helper start time or last reset time (whichever is later) until the last
+     * stop time or the current time (whichever is earlier).
+     *
+     * @return A WifiPhyTraceStatistics object containing current reception statistics.
+     */
+    WifiPhyTraceStatistics GetStatistics() const;
+
+    /**
+     * Retrieves reception statistics for a given node, device, and link.
+     * @param node Ptr to Node.
+     * @param deviceId Device identifier (optional, defaults to 0).
+     * @param linkId Link identifier (optional, defaults to 0).
+     * @return WifiPhyTraceStatistics object with current reception stats.
+     */
+    WifiPhyTraceStatistics GetStatistics(Ptr<Node> node,
+                                         uint32_t deviceId = 0,
+                                         uint8_t linkId = 0) const;
+
+    /**
+     * Retrieves reception statistics for a given node, device, and link.
+     * @param nodeId Node identifier.
+     * @param deviceId Device identifier (optional, defaults to 0).
+     * @param linkId Link identifier (optional, defaults to 0).
+     * @return WifiPhyTraceStatistics object with current reception stats.
+     */
+    WifiPhyTraceStatistics GetStatistics(uint32_t nodeId,
+                                         uint32_t deviceId = 0,
+                                         uint8_t linkId = 0) const;
+
+    /**
+     * Starts the collection of statistics from a specified start time.
+     * @param startTime The time to start collecting statistics.
+     */
+    void Start(Time startTime);
+
+    /**
+     * Stops the collection of statistics at a specified time.
+     * @param stopTime The time to stop collecting statistics.
+     */
+    void Stop(Time stopTime);
+
+    /**
+     * Resets the current statistics, clearing all counts and PPDU records.
+     */
+    void Reset();
+
+    /**
+     * Accesses a vector of saved and completed PPDU reception records.
+     * @return A constant reference to a vector of WifiPpduRxRecord instances.
+     */
+    const std::vector<WifiPpduRxRecord>& GetPpduRecords() const;
+
+    /**
+     * Accesses PPDU reception records for a specific node, device, and link.
+     *
+     * Because the return value could be null if the specified node/device/link do not have any
+     * records, this method returns a std::optional object, and because we are passing the
+     * underlying vector by const reference to avoid a copy, it must be wrapped by
+     * std::reference_wrapper. See the example program wifi-phy-reception-trace-example.cc for an
+     * example of how to use the value returned.
+     *
+     * @param nodeId The ID of the node.
+     * @param deviceId The ID of the WifiNetDevice (optional, defaults to 0).
+     * @param linkId The ID of the link (optional, defaults to 0).
+     * @return A reference to a vector of WifiPpduRxRecord instances.
+     */
+    std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>> GetPpduRecords(
+        uint32_t nodeId,
+        uint32_t deviceId = 0,
+        uint8_t linkId = 0) const;
+
+    /**
+     * Print statistics for all nodes, devices, and links during the collection period.
+     */
+    void PrintStatistics() const;
+
+    /**
+     * Prints statistics collected in the period for a specific node, device, and link.
+     * @param node Ptr to Node.
+     * @param deviceId Device identifier (optional, defaults to 0).
+     * @param linkId Link identifier (optional, defaults to 0).
+     */
+    void PrintStatistics(Ptr<Node> node, uint32_t deviceId = 0, uint8_t linkId = 0) const;
+
+    /**
+     * Prints statistics collected in the period for a specific node, device, and link.
+     * @param nodeId Node identifier.
+     * @param deviceId Device identifier (optional, defaults to 0).
+     * @param linkId Link identifier (optional, defaults to 0).
+     */
+    void PrintStatistics(uint32_t nodeId, uint32_t deviceId = 0, uint8_t linkId = 0) const;
+
+  private:
+    /**
+     * Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
+     * @param nodes The NodeContainer to which traces are to be connected.
+     * @param MacToNodeMap A mapping from MAC address to node ID.
+     */
+    void Enable(NodeContainer nodes, const std::map<Mac48Address, uint32_t>& MacToNodeMap);
+
+    /**
+     * Populates the mapping of MAC addresses to node IDs for a given set of nodes.
+     * @param nodes The container of nodes for which to populate the MAC address to node ID mapping.
+     * @return a copy of the std::map container
+     */
+    std::map<Mac48Address, uint32_t> MapMacAddressesToNodeIds(NodeContainer nodes) const;
+
+    Ptr<WifiPhyRxTraceSink> m_traceSink; ///< Pointer to the current trace sink object.
+};
+
+/**
+ * @class WifiPhyRxTraceSink
+ * @brief Sink class for capturing and analyzing PHY layer reception events in Wi-Fi networks.
+ *
+ * The WifiPhyRxTraceSink class acts as a comprehensive sink for events related to the
+ * reception of signals at the Physical Layer (PHY) of Wi-Fi networks. It is designed to facilitate
+ * the detailed analysis and tracing of reception activities, and the management of reception data
+ * across nodes, devices, and links. This class supports the capture and analysis of detailed
+ * reception records, including successful and failed receptions, and offers capabilities to
+ * manage the collection of reception statistics.
+ *
+ * Features include:
+ * - Unique tag generation for tracking individual reception events.
+ * - Access to detailed PPDU reception records for analysis.
+ * - Management of reception statistics collection through start, stop, and reset operations.
+ * - Mapping of MAC addresses to node IDs for network element identification.
+ * - Handling of PHY signal transmission and reception events for detailed outcome logging.
+ * - Tracking and analysis of overlapping reception events for interference assessment.
+ */
+class WifiPhyRxTraceSink : public Object
+{
+  public:
+    /**
+     * Constructor.
+     */
+    WifiPhyRxTraceSink();
+
+    /**
+     * Retrieves the TypeId of the class.
+     * @return The TypeId of the WifiPhyRxTraceSink class.
+     */
+    static TypeId GetTypeId();
+
+    /**
+     * @brief Generating unique tags for more than one instance of a WifiPpdu object
+     *
+     * This class is responsible for generating unique identifiers for each received
+     * WifiPpdu.  The WifiPpdu UID is not sufficient because there can be more than one
+     * record per WifiPpdu.
+     */
+    class UniqueTagGenerator
+    {
+      public:
+        /**
+         * Generates a unique tag for a WifiPpdu. Uses an internal counter and a set of
+         * previously used tags to ensure that each generated tag is unique, allowing accurate
+         * tracking of received frames.
+         * @param ppduUid The PPDU UID to generate a unique tag for.
+         * @return uint64_t The generated unique tag.
+         */
+        uint64_t GenerateUniqueTag(uint64_t ppduUid);
+
+      private:
+        uint64_t counter{0};         ///< Counter to help generate unique tags.
+        std::set<uint64_t> usedTags; ///< Set of already used tags.
+    };
+
+    UniqueTagGenerator m_tagGenerator; ///< Instance of UniqueTagGenerator used for generating
+                                       ///< unique reception tags.
+
+    /**
+     * Provides access to all saved and completed PPDU reception records across all nodes,
+     * WifiNetDevices, and links.
+     * @return A constant reference to a vector of WifiPpduRxRecord instances.
+     */
+    const std::vector<WifiPpduRxRecord>& GetPpduRecords() const;
+
+    /**
+     * Provides access to PPDU reception records for a specific node, device, and link.
+     * @param nodeId The ID of the node.
+     * @param deviceId The ID of the WifiNetDevice (optional, defaults to 0).
+     * @param linkId The ID of the link (optional, defaults to 0).
+     * @return A constant reference to a vector of WifiPpduRxRecord instances.
+     */
+    std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>> GetPpduRecords(
+        uint32_t nodeId,
+        uint32_t deviceId = 0,
+        uint8_t linkId = 0) const;
+
+    /**
+     * Creates a vector with all completed WiFi reception records to be returned by the
+     * GetPpduRecords(). This is only called if no specific node, device or link is
+     * provided.
+     */
+    void CreateVectorFromRecords();
+
+    /**
+     * Provides a custom mapping of MAC addresses to intended receiver node IDs. This mapping is
+     * crucial for identifying the nodes involved in reception events based on their MAC addresses,
+     * facilitating the analysis of network dynamics at the PHY layer.
+     * @param MacAddressToNodeIdMap A mapping from MAC addresses to node IDs.
+     */
+    void SetMapMacAddressToNodeId(const std::map<Mac48Address, uint32_t>& MacAddressToNodeIdMap);
+
+    /**
+     * Retrieves the frequency and channel number used by a specific link.
+     * @param node The node ID.
+     * @param deviceId The device ID of the WifiNetDevice.
+     * @param link The link ID.
+     * @return A pair containing the channel number (uint8_t) and frequency (uint16_t).
+     */
+    std::optional<std::pair<uint8_t, uint16_t>> GetChannelInfo(uint32_t node,
+                                                               uint32_t deviceId,
+                                                               int link) const;
+
+    /**
+     * Starts the statistics collection period from a specified start time. Ongoing PPDUs when this
+     * method is called will be counted towards this statistics collection period.
+     */
+    void Start();
+
+    /**
+     * Stops the statistics collection period at a specified time. This method ensures that
+     * incomplete PPDUs at the end of the collection period are not included in the current
+     * statistics count.
+     */
+    void Stop();
+
+    /**
+     * Resets the statistics collection, clearing all counts and discarding all fully completed PPDU
+     * records. This allows for a fresh start in data collection and analysis.
+     */
+    void Reset();
+
+    /**
+     * Translates a context string to a link ID, facilitating the association of events with
+     * specific links in the network.
+     * @param context The context string.
+     * @return The link ID associated with the context.
+     */
+    int ContextToLinkId(std::string context) const;
+
+    /**
+     * Translates a context string to a device ID, enabling the identification of devices involved
+     * in reception events based on context information.
+     * @param context The context string.
+     * @return The device ID associated with the context.
+     */
+    int ContextToDeviceId(std::string context) const;
+
+    /**
+     * Translates a context string to a node ID.
+     * @param context The context string to translate.
+     * @return The corresponding node ID, facilitating the identification of the node involved in a
+     * reception event.
+     */
+    uint32_t ContextToNodeId(std::string context) const;
+
+    /**
+     * Translate a context string to a colon-delimited tuple "0:0:0" where the first element
+     * is a node ID, second is a device ID, third is a link ID
+     * @param context The context string to translate.
+     * @return The tuple of node, device, and link IDs
+     */
+    std::string ContextToTuple(std::string context) const;
+
+    /**
+     * Handles the event of a PHY signal transmission.
+     * @param context The context string, providing situational information about the transmission.
+     * @param ppdu The Wi-Fi PPDU being transmitted.
+     * @param txVector The transmission vector, detailing the parameters of the transmission.
+     */
+    void PhySignalTransmission(std::string context,
+                               Ptr<const WifiPpdu> ppdu,
+                               const WifiTxVector& txVector);
+
+    /**
+     * @brief Handles the event of a Wi-Fi PPDU arrival.
+     *
+     * @param context The context string, offering contextual information about the signal
+     * reception.
+     * @param ppdu The received WifiPpdu
+     * @param rxPower The power level at which the signal was received, indicating the signal's
+     * strength.
+     * @param duration The duration of the signal, offering temporal information about the reception
+     * event.
+     */
+    void PhySignalArrival(std::string context,
+                          Ptr<const WifiPpdu> ppdu,
+                          double rxPower,
+                          Time duration);
+
+    /**
+     * @brief Handles the event of a PHY signal arrival from a SpectrumChannel.
+     *
+     * @param context The context string, offering contextual information about the signal
+     * reception.
+     * @param signal The received signal parameters, detailing the characteristics of the arriving
+     * signal.
+     * @param senderNodeId The ID of the node sending the signal, providing insight into the source
+     * of the signal.
+     * @param rxPower The power level at which the signal was received, indicating the signal's
+     * strength.
+     * @param duration The duration of the signal, offering temporal information about the reception
+     * event.
+     */
+    void SpectrumPhySignalArrival(std::string context,
+                                  Ptr<const SpectrumSignalParameters> signal,
+                                  uint32_t senderNodeId,
+                                  double rxPower,
+                                  Time duration);
+
+    /**
+     * Maps nodes to links and channels, creating a structured association between network
+     * elements and their communication channels. This mapping is essential for understanding
+     * what frequency and channel number is used for a given link.
+     * @param nodes NodeContainer of all nodes whose MAC address is going to be link to their
+     * NodeID.
+     */
+    void MapNodeToLinkToChannel(NodeContainer nodes);
+
+    /**
+     * Returns statistics on the count of successful and failed PPDUs with unicast data, and their
+     * MPDUs, across all nodes, devices, and links.
+     * @return A WifiPhyTraceStatistics object containing the current statistics. This method does
+     * not reset the collected statistics, allowing for continuous accumulation of data over time.
+     */
+    WifiPhyTraceStatistics GetStatistics() const;
+
+    /**
+     * Returns statistics on the count of successful and failed PPDUs with unicast data, and their
+     * MPDUs, for a specific node, device, and link.
+     * @param nodeId The node ID from which to get the statistics.
+     * @param deviceId The device ID from which to get the statistics.
+     * @param linkId The link ID from which to get the statistics.
+     * @return A WifiPhyTraceStatistics object containing the current statistics. This method does
+     * not reset the collected statistics, allowing for continuous accumulation of data over time.
+     */
+    WifiPhyTraceStatistics GetStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const;
+
+    /**
+     * Updates the information for signals currently being received by a node.
+     * @param nodeId The node ID for which to update the reception information.
+     * @param deviceId The device ID on the node for which to update the information.
+     * @param linkId The link ID associated with the ongoing reception.
+     */
+    void UpdateCurrentlyReceivedSignal(uint32_t nodeId, uint32_t deviceId, uint8_t linkId);
+
+    /**
+     * Records the outcome of a PPDU transmission, including the signal info, and the success or
+     * failure status of each MPDU within the PPDU.
+     * @param context Descriptive context for the PPDU outcome.
+     * @param ppdu Pointer to the PPDU whose outcome is being recorded.
+     * @param signal Information about the received signal.
+     * @param txVector The transmission vector used for the PPDU.
+     * @param statusPerMpdu A vector indicating the success (true) or failure (false) of each MPDU.
+     */
+    void PpduOutcome(std::string context,
+                     Ptr<const WifiPpdu> ppdu,
+                     RxSignalInfo signal,
+                     const WifiTxVector& txVector,
+                     const std::vector<bool>& statusPerMpdu);
+
+    /**
+     * Logs the drop of a PPDU at the PHY layer, detailing the context and reason for the drop.
+     * @param context Descriptive context for the PPDU drop.
+     * @param ppdu Pointer to the PPDU that was dropped.
+     * @param reason The reason for the PPDU drop, represented as a WifiPhyRxfailureReason.
+     */
+    void PhyPpduDrop(std::string context, Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason);
+
+    /**
+     * Handles the end of a PHY reception event, logging the conclusion of a reception and its
+     * associated details.
+     * @param nodeId The node ID where the reception ended.
+     * @param deviceId The device ID on the node where the reception took place.
+     * @param rxTag The unique reception tag associated with the reception event.
+     * @param ppduUid The PPDU UID of the received WifiPpdu
+     */
+    void PhyRxEnd(uint32_t nodeId, uint32_t deviceId, uint64_t rxTag, uint64_t ppduUid);
+
+    /**
+     * Handles the conclusion of a transmission event, facilitating the logging of transmission
+     * outcomes.
+     * @param nodeId The node ID from which the transmission originated.
+     * @param deviceId The device ID on the node that performed the transmission.
+     * @param ppduRecord The WifiPpduRxRecord representing the concluded transmission.
+     */
+    void EndTx(uint32_t nodeId, uint32_t deviceId, WifiPpduRxRecord ppduRecord);
+
+    /**
+     * Counts and aggregates PHY layer statistics including receptions, transmissions, and
+     * performance metrics (Success, Failure, Overlap) of unicast data PPDUs and MPDUs across all
+     * nodes.
+     * @return WifiPhyTraceStatistics object containing aggregated statistics for all nodes.
+     */
+    WifiPhyTraceStatistics CountStatistics() const;
+
+    /**
+     * Counts statistics related to PHY layer receptions, transmissions, and performance metrics
+     * such as Success, Failure or Overlap of a PPDU containing unicast data, and the MPDUs within,
+     * for the specific node,
+     * device and link.
+     * @param nodeId Node identifier.
+     * @param deviceId Device identifier.
+     * @param linkId Link identifier.
+     * @return WifiPhyTraceStatistics object with current reception stats.
+     */
+    WifiPhyTraceStatistics CountStatistics(uint32_t nodeId,
+                                           uint32_t deviceId,
+                                           uint8_t linkId) const;
+
+    /**
+     * Prints a summary of the statistics collected, offering a concise overview of PHY layer
+     * performance and reception outcomes for all nodes, devices and links.
+     */
+    void PrintStatistics() const;
+
+    /**
+     * Prints statistics collected in the period for a node, device, and link.
+     * @param nodeId Node identifier.
+     * @param deviceId Device identifier.
+     * @param linkId Link identifier.
+     */
+    void PrintStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const;
+
+    /**
+     * @brief Returns whether the collection period is active
+     * @return Whether the collection period is active
+     */
+    bool IsCollectionPeriodActive() const;
+
+    /**
+     * @brief Maps a reception tag to the corresponding WifiPpduRxRecord.
+     *
+     * This map links each unique reception tag generated upon receiving a
+     * frame to the corresponding detailed reception record (WifiPpduRxRecord). It is
+     * refreshed every time a new reception record is created.
+     */
+    std::map<uint64_t, WifiPpduRxRecord> m_rxTagToPpduRecord;
+
+    /**
+     * @brief Stores records of PPDUs that have completed reception, organized by node, device, and
+     * link.
+     *
+     * This nested map structure is updated each time a WifiPpduRxRecord is finalized,
+     * keeping a history of all completed packet receptions across different nodes,
+     * devices, and links.
+     */
+    std::map<uint32_t, std::map<uint32_t, std::map<uint8_t, std::vector<WifiPpduRxRecord>>>>
+        m_completedRecords;
+
+    /**
+     * @brief Stores a flat vector of all records of PPDUs that have completed reception.
+     *
+     * This vector is updated upon the request of GetPpduRecords(),
+     * maintaining all packet receptions.
+     */
+    std::vector<WifiPpduRxRecord> m_records;
+
+    /**
+     * @brief Tracks ongoing frames being transmitted or received per node, device, and link.
+     *
+     * This map associates each node (by its ID) with nested maps keyed by device and link IDs, each
+     * containing vectors of WifiPpduRxRecords. It enables the tracking of current packet
+     * transmissions and receptions.
+     */
+    std::map<uint32_t, std::map<uint32_t, std::map<uint32_t, std::vector<WifiPpduRxRecord>>>>
+        m_nodeDeviceLinkRxRecords;
+
+    /**
+     * @brief Maps each reception tag to a list of overlapping WifiPpduRxRecords.
+     *
+     * For each unique reception tag, this map stores a vector of WifiPpduRxRecords that
+     * overlap with the record corresponding to the tag.
+     */
+    std::map<uint64_t, std::vector<WifiPpduRxRecord>> m_rxTagToListOfOverlappingPpduRecords;
+
+    /**
+     * @brief Aids in correlating PHY reception drops and outcomes with specific reception tags.
+     *
+     * This complex map structure is used to navigate from node and device IDs, and link and packet
+     * IDs (PIDs), to the corresponding reception tag.
+     */
+    std::map<uint64_t, std::map<uint64_t, std::map<uint64_t, std::map<uint64_t, uint64_t>>>>
+        m_nodeDeviceLinkPidToRxId;
+
+    /**
+     * @brief Maps WifiPpdu UIDs to WifiPpduRxRecord tags stored by transmitter.
+     *
+     * This map allows a transmit-side PPDU record to be fetched based on the WifiPpdu UID.
+     */
+    std::map<uint64_t, uint64_t> m_ppduUidToTxTag;
+
+    /**
+     * @brief Maps MAC addresses to node IDs.
+     *
+     * This mapping facilitates the identification of nodes within the network based on the MAC
+     * addresses observed in reception events. By translating MAC addresses to node IDs, this map
+     * enables the association of reception data with specific network nodes.
+     */
+    std::map<Mac48Address, uint32_t> m_macAddressToNodeId;
+
+    /**
+     * Maps node IDs to device IDs and further to link IDs, associating each with a pair consisting
+     * of the channel number and frequency. This structure is vital for understanding the channel
+     * and frequency utilization across different links.
+     */
+    std::map<uint32_t, std::map<uint32_t, std::map<int, std::pair<uint8_t, uint16_t>>>>
+        m_nodeToDeviceToLinkToChannelInfo;
+
+  private:
+    /**
+     * Flag indicating whether to keep a record of certain statistics or events for analysis. This
+     * boolean flag can be toggled to control the granularity and scope of data collection, enabling
+     * customization of the analysis to focus on specific times of interest.
+     */
+    bool m_statisticsCollectionPeriodStarted;
+
+    /**
+     * Update the passed-in statistics object with statistics from the passed-in record.
+     * \param statistics The WifiPhyTraceStatistics object to modify
+     * \param record The WifiPpduRxRecord to examine
+     */
+    void CountStatisticsForRecord(WifiPhyTraceStatistics& statistics,
+                                  const WifiPpduRxRecord& record) const;
+
+}; // class WifiPhyRxTraceSink
+
+// Non-member function declarations
+
+/**
+ * @brief Checks if two WifiPpduRxRecord objects are equal.
+ *
+ * Compares two WifiPpduRxRecord objects to determine if they are equal. Two objects
+ * are considered equal if all their corresponding counts have the same values.
+ *
+ * @param lhs The left-hand side WifiPpduRxRecord object in the comparison.
+ * @param rhs The right-hand side WifiPpduRxRecord object in the comparison.
+ * @return true if the objects are equal, false otherwise.
+ */
+bool operator==(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs);
+
+/**
+ * @brief Checks if two WifiPpduRxRecord objects are not equal.
+ *
+ * Compares two WifiPpduRxRecord objects to determine if they are not equal. Two objects
+ * are considered not equal if at least one of their corresponding counts have different values.
+ *
+ * @param lhs The left-hand side WifiPpduRxRecord object in the comparison.
+ * @param rhs The right-hand side WifiPpduRxRecord object in the comparison.
+ * @return true if the objects are not equal, false otherwise.
+ */
+bool operator!=(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs);
+
+/**
+ * @brief Determines if one WifiPpduRxRecord object is less than another.
+ *
+ * Compares two WifiPpduRxRecord objects to determine if the left-hand side object is
+ * considered less than the right-hand side object based on a specific criteria of comparison,
+ * such as a key property value.
+ *
+ * @note The specific criteria for comparison should be defined and consistent.
+ *
+ * @param lhs The left-hand side WifiPpduRxRecord object in the comparison.
+ * @param rhs The right-hand side WifiPpduRxRecord object in the comparison.
+ * @return true if lhs is considered less than rhs, false otherwise.
+ */
+bool operator<(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs);
+
+/**
+ * @brief Checks if two WifiPhyTraceStatistics objects are equal.
+ *
+ * Determines if two WifiPhyTraceStatistics objects are equal by comparing their counts.
+ * Equality is based on the values of all relevant statistical counts being identical.
+ *
+ * @param lhs The left-hand side WifiPhyTraceStatistics object in the comparison.
+ * @param rhs The right-hand side WifiPhyTraceStatistics object in the comparison.
+ * @return true if all counts are equal, false otherwise.
+ */
+bool operator==(const WifiPhyTraceStatistics& lhs, const WifiPhyTraceStatistics& rhs);
+
+/**
+ * @brief Checks if two WifiPhyTraceStatistics objects are not equal.
+ *
+ * Determines if two WifiPhyTraceStatistics objects are not equal by comparing their counts.
+ * Non-equality is based on any of the relevant statistical counts having different values.
+ *
+ * @param lhs The left-hand side WifiPhyTraceStatistics object in the comparison.
+ * @param rhs The right-hand side WifiPhyTraceStatistics object in the comparison.
+ * @return true if any property is different, false otherwise.
+ */
+bool operator!=(const WifiPhyTraceStatistics& lhs, const WifiPhyTraceStatistics& rhs);
+
+/**
+ * @brief Adds two WifiPhyTraceStatistics objects.
+ *
+ * Combines two WifiPhyTraceStatistics objects by summing their counts.
+ * This can be useful for aggregating statistics from multiple sources or time periods.
+ *
+ * @param lhs The left-hand side WifiPhyTraceStatistics object to be added.
+ * @param rhs The right-hand side WifiPhyTraceStatistics object to be added.
+ * @return A new WifiPhyTraceStatistics object that is the result of the addition.
+ */
+WifiPhyTraceStatistics operator+(const WifiPhyTraceStatistics& lhs,
+                                 const WifiPhyTraceStatistics& rhs);
+
+} // namespace ns3
+
+#endif /* WIFI_PHY_RX_TRACE_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-radio-energy-model-helper.cc ns-3.42/src/wifi/helper/wifi-radio-energy-model-helper.cc
--- ns-3.41/src/wifi/helper/wifi-radio-energy-model-helper.cc	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/wifi-radio-energy-model-helper.cc	2024-05-29 15:29:47.196073800 -0700
@@ -61,8 +61,8 @@
  * Private function starts here.
  */
 
-Ptr<DeviceEnergyModel>
-WifiRadioEnergyModelHelper::DoInstall(Ptr<NetDevice> device, Ptr<EnergySource> source) const
+Ptr<energy::DeviceEnergyModel>
+WifiRadioEnergyModelHelper::DoInstall(Ptr<NetDevice> device, Ptr<energy::EnergySource> source) const
 {
     NS_ASSERT(device);
     NS_ASSERT(source);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/helper/wifi-radio-energy-model-helper.h ns-3.42/src/wifi/helper/wifi-radio-energy-model-helper.h
--- ns-3.41/src/wifi/helper/wifi-radio-energy-model-helper.h	2024-02-09 14:44:08.573794800 -0800
+++ ns-3.42/src/wifi/helper/wifi-radio-energy-model-helper.h	2024-05-29 15:29:47.196073800 -0700
@@ -86,8 +86,8 @@
      *
      * Implements DeviceEnergyModel::Install.
      */
-    Ptr<DeviceEnergyModel> DoInstall(Ptr<NetDevice> device,
-                                     Ptr<EnergySource> source) const override;
+    Ptr<energy::DeviceEnergyModel> DoInstall(Ptr<NetDevice> device,
+                                             Ptr<energy::EnergySource> source) const override;
 
   private:
     ObjectFactory m_radioEnergy; ///< radio energy
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/adhoc-wifi-mac.cc ns-3.42/src/wifi/model/adhoc-wifi-mac.cc
--- ns-3.41/src/wifi/model/adhoc-wifi-mac.cc	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/adhoc-wifi-mac.cc	2024-05-29 15:29:47.196073800 -0700
@@ -59,6 +59,12 @@
     NS_LOG_FUNCTION(this);
 }
 
+void
+AdhocWifiMac::DoCompleteConfig()
+{
+    NS_LOG_FUNCTION(this);
+}
+
 bool
 AdhocWifiMac::CanForwardPacketsTo(Mac48Address to) const
 {
@@ -72,7 +78,7 @@
     if (GetWifiRemoteStationManager()->IsBrandNew(to))
     {
         // In ad hoc mode, we assume that every destination supports all the rates we support.
-        if (GetHtSupported())
+        if (GetHtSupported(SINGLE_LINK_OP_ID))
         {
             GetWifiRemoteStationManager()->AddAllSupportedMcs(to);
             GetWifiRemoteStationManager()->AddStationHtCapabilities(
@@ -90,6 +96,12 @@
             GetWifiRemoteStationManager()->AddStationHeCapabilities(
                 to,
                 GetHeCapabilities(SINGLE_LINK_OP_ID));
+            if (Is6GhzBand(SINGLE_LINK_OP_ID))
+            {
+                GetWifiRemoteStationManager()->AddStationHe6GhzCapabilities(
+                    to,
+                    GetHe6GhzBandCapabilities(SINGLE_LINK_OP_ID));
+            }
         }
         if (GetEhtSupported())
         {
@@ -139,7 +151,7 @@
         hdr.SetType(WIFI_MAC_DATA);
     }
 
-    if (GetHtSupported())
+    if (GetHtSupported(SINGLE_LINK_OP_ID))
     {
         hdr.SetNoOrder(); // explicitly set to 0 for the time being since HT control field is not
                           // yet implemented (set it to 1 when implemented)
@@ -185,7 +197,7 @@
     if (GetWifiRemoteStationManager()->IsBrandNew(from))
     {
         // In ad hoc mode, we assume that every destination supports all the rates we support.
-        if (GetHtSupported())
+        if (GetHtSupported(SINGLE_LINK_OP_ID))
         {
             GetWifiRemoteStationManager()->AddAllSupportedMcs(from);
             GetWifiRemoteStationManager()->AddStationHtCapabilities(
@@ -222,7 +234,7 @@
         }
         else
         {
-            ForwardUp(mpdu->GetPacket()->Copy(), from, to);
+            ForwardUp(mpdu->GetPacket(), from, to);
         }
         return;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/adhoc-wifi-mac.h ns-3.42/src/wifi/model/adhoc-wifi-mac.h
--- ns-3.41/src/wifi/model/adhoc-wifi-mac.h	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/adhoc-wifi-mac.h	2024-05-29 15:29:47.196073800 -0700
@@ -50,6 +50,7 @@
 
   private:
     void Receive(Ptr<const WifiMpdu> mpdu, uint8_t linkId) override;
+    void DoCompleteConfig() override;
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/ap-wifi-mac.cc ns-3.42/src/wifi/model/ap-wifi-mac.cc
--- ns-3.41/src/wifi/model/ap-wifi-mac.cc	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/ap-wifi-mac.cc	2024-05-29 15:29:47.196073800 -0700
@@ -85,6 +85,25 @@
                           BooleanValue(true),
                           MakeBooleanAccessor(&ApWifiMac::SetBeaconGeneration),
                           MakeBooleanChecker())
+            .AddAttribute("FdBeaconInterval6GHz",
+                          "Time between a Beacon frame and a FILS Discovery (FD) frame or between "
+                          "two FD frames to be sent on a 6GHz link. A value of zero disables the "
+                          "transmission of FD frames.",
+                          TimeValue(Time{0}),
+                          MakeTimeAccessor(&ApWifiMac::m_fdBeaconInterval6GHz),
+                          MakeTimeChecker())
+            .AddAttribute("FdBeaconIntervalNon6GHz",
+                          "Time between a Beacon frame and a FILS Discovery (FD) frame or between "
+                          "two FD frames to be sent on a non-6GHz link. A value of zero disables "
+                          "the transmission of FD frames.",
+                          TimeValue(Time{0}),
+                          MakeTimeAccessor(&ApWifiMac::m_fdBeaconIntervalNon6GHz),
+                          MakeTimeChecker())
+            .AddAttribute("SendUnsolProbeResp",
+                          "Send unsolicited broadcast Probe Response instead of FILS Discovery",
+                          BooleanValue(false),
+                          MakeBooleanAccessor(&ApWifiMac::m_sendUnsolProbeResp),
+                          MakeBooleanChecker())
             .AddAttribute("EnableNonErpProtection",
                           "Whether or not protection mechanism should be used when non-ERP STAs "
                           "are present within the BSS."
@@ -97,6 +116,70 @@
                           TimeValue(MilliSeconds(20)),
                           MakeTimeAccessor(&ApWifiMac::m_bsrLifetime),
                           MakeTimeChecker())
+            .AddAttribute(
+                "CwMinsForSta",
+                "The CW min values that the AP advertises in EDCA Parameter Set elements and the "
+                "associated stations will use. The value of this attribute is an AC-indexed map "
+                "containing the CW min values for given ACs for all the links (sorted in "
+                "increasing order of link ID). If no values are provided for an AC, the same "
+                "values used by the AP are advertised. In case a string is used to set this "
+                "attribute, the string shall contain the pairs separated by a semicolon (;); "
+                "in every pair, the AC index and the list of values are separated by a blank "
+                "space, and the values of a list are separated by a comma (,) without spaces. "
+                "E.g. \"BE 31,31,31; VI 15,15,15\" defines the CW min values for AC BE and AC VI "
+                "for an AP MLD having three links.",
+                StringValue(""),
+                MakeAttributeContainerAccessor<UintAccessParamsPairValue, ';'>(
+                    &ApWifiMac::m_cwMinsForSta),
+                GetUintAccessParamsChecker<uint32_t>())
+            .AddAttribute(
+                "CwMaxsForSta",
+                "The CW max values that the AP advertises in EDCA Parameter Set elements and the "
+                "associated stations will use. The value of this attribute is an AC-indexed map "
+                "containing the CW max values for given ACs for all the links (sorted in "
+                "increasing order of link ID). If no values are provided for an AC, the same "
+                "values used by the AP are advertised. In case a string is used to set this "
+                "attribute, the string shall contain the pairs separated by a semicolon (;); "
+                "in every pair, the AC index and the list of values are separated by a blank "
+                "space, and the values of a list are separated by a comma (,) without spaces. "
+                "E.g. \"BE 31,31,31; VI 15,15,15\" defines the CW max values for AC BE and AC VI "
+                "for an AP MLD having three links.",
+                StringValue(""),
+                MakeAttributeContainerAccessor<UintAccessParamsPairValue, ';'>(
+                    &ApWifiMac::m_cwMaxsForSta),
+                GetUintAccessParamsChecker<uint32_t>())
+            .AddAttribute(
+                "AifsnsForSta",
+                "The AIFSN values that the AP advertises in EDCA Parameter Set elements and the "
+                "associated stations will use. The value of this attribute is an AC-indexed map "
+                "containing the AIFSN values for given ACs for all the links (sorted in "
+                "increasing order of link ID). If no values are provided for an AC, the same "
+                "values used by the AP are advertised. In case a string is used to set this "
+                "attribute, the string shall contain the pairs separated by a semicolon (;); "
+                "in every pair, the AC index and the list of values are separated by a blank "
+                "space, and the values of a list are separated by a comma (,) without spaces. "
+                "E.g. \"BE 3,3,3; VI 2,2,2\" defines the AIFSN values for AC BE and AC VI "
+                "for an AP MLD having three links.",
+                StringValue(""),
+                MakeAttributeContainerAccessor<UintAccessParamsPairValue, ';'>(
+                    &ApWifiMac::m_aifsnsForSta),
+                GetUintAccessParamsChecker<uint8_t>())
+            .AddAttribute(
+                "TxopLimitsForSta",
+                "The TXOP limit values that the AP advertises in EDCA Parameter Set elements and "
+                "the associated stations will use. The value of this attribute is an AC-indexed "
+                "map containing the TXOP limit values for given ACs for all the links (sorted in "
+                "increasing order of link ID). If no values are provided for an AC, the same "
+                "values used by the AP are advertised. In case a string is used to set this "
+                "attribute, the string shall contain the pairs separated by a semicolon (;); "
+                "in every pair, the AC index and the list of values are separated by a blank "
+                "space, and the values of a list are separated by a comma (,) without spaces. "
+                "E.g. \"BE 3200us,3200us,3200us; VI 2400us,2400us,2400us\" defines the TXOP limit "
+                "values for AC BE and AC VI for an AP MLD having three links.",
+                StringValue(""),
+                MakeAttributeContainerAccessor<TimeAccessParamsPairValue, ';'>(
+                    &ApWifiMac::m_txopLimitsForSta),
+                GetTimeAccessParamsChecker())
             .AddTraceSource("AssociatedSta",
                             "A station associated with this access point.",
                             MakeTraceSourceAccessor(&ApWifiMac::m_assocLogger),
@@ -108,11 +191,32 @@
     return tid;
 }
 
+template <class T>
+Ptr<const AttributeChecker>
+ApWifiMac::GetUintAccessParamsChecker()
+{
+    return MakeAttributeContainerChecker<UintAccessParamsPairValue, ';'>(
+        MakePairChecker<EnumValue<AcIndex>,
+                        AttributeContainerValue<UintegerValue, ',', std::vector>>(
+            MakeEnumChecker(AC_BE, "BE", AC_BK, "BK", AC_VI, "VI", AC_VO, "VO"),
+            MakeAttributeContainerChecker<UintegerValue, ',', std::vector>(
+                MakeUintegerChecker<T>())));
+}
+
+Ptr<const AttributeChecker>
+ApWifiMac::GetTimeAccessParamsChecker()
+{
+    return MakeAttributeContainerChecker<TimeAccessParamsPairValue, ';'>(
+        MakePairChecker<EnumValue<AcIndex>, AttributeContainerValue<TimeValue, ',', std::vector>>(
+            MakeEnumChecker(AC_BE, "BE", AC_BK, "BK", AC_VI, "VI", AC_VO, "VO"),
+            MakeAttributeContainerChecker<TimeValue, ',', std::vector>(MakeTimeChecker())));
+}
+
 ApWifiMac::ApWifiMac()
     : m_enableBeaconGeneration(false)
 {
     NS_LOG_FUNCTION(this);
-    m_beaconTxop = CreateObject<Txop>(CreateObject<WifiMacQueue>(AC_BEACON));
+    m_beaconTxop = CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BEACON"));
     m_beaconTxop->SetTxMiddle(m_txMiddle);
 
     // Let the lower layers know that we are acting as an AP.
@@ -153,11 +257,11 @@
 }
 
 void
-ApWifiMac::ConfigureStandard(WifiStandard standard)
+ApWifiMac::DoCompleteConfig()
 {
-    NS_LOG_FUNCTION(this << standard);
-    WifiMac::ConfigureStandard(standard);
+    NS_LOG_FUNCTION(this);
     m_beaconTxop->SetWifiMac(this);
+    // DCF behavior may be edited here; the default is PIFS access with zero backoff
     m_beaconTxop->SetAifsns(std::vector<uint8_t>(GetNLinks(), 1));
     m_beaconTxop->SetMinCws(std::vector<uint32_t>(GetNLinks(), 0));
     m_beaconTxop->SetMaxCws(std::vector<uint32_t>(GetNLinks(), 0));
@@ -237,7 +341,10 @@
 {
     NS_LOG_FUNCTION(this << stream);
     m_beaconJitter->SetStream(stream);
-    return 1;
+    auto currentStream = stream + 1;
+    currentStream += m_beaconTxop->AssignStreams(currentStream);
+    currentStream += WifiMac::AssignStreams(currentStream);
+    return (currentStream - stream);
 }
 
 void
@@ -460,7 +567,7 @@
     // must have its MSB set to 1 (must be treated as a Basic Rate)
     // Also the standard mentioned that at least 1 element should be included in the SupportedRates
     // the rest can be in the ExtendedSupportedRates
-    if (GetHtSupported())
+    if (GetHtSupported(linkId))
     {
         for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
         {
@@ -523,35 +630,51 @@
     Time txopLimit;
 
     edca = GetQosTxop(AC_BE);
-    txopLimit = edca->GetTxopLimit(linkId);
     edcaParameters.SetBeAci(0);
-    edcaParameters.SetBeCWmin(edca->GetMinCw(linkId));
-    edcaParameters.SetBeCWmax(edca->GetMaxCw(linkId));
-    edcaParameters.SetBeAifsn(edca->GetAifsn(linkId));
+    edcaParameters.SetBeCWmin(m_cwMinsForSta.contains(AC_BE) ? m_cwMinsForSta.at(AC_BE).at(linkId)
+                                                             : edca->GetMinCw(linkId));
+    edcaParameters.SetBeCWmax(m_cwMaxsForSta.contains(AC_BE) ? m_cwMaxsForSta.at(AC_BE).at(linkId)
+                                                             : edca->GetMaxCw(linkId));
+    edcaParameters.SetBeAifsn(m_aifsnsForSta.contains(AC_BE) ? m_aifsnsForSta.at(AC_BE).at(linkId)
+                                                             : edca->GetAifsn(linkId));
+    txopLimit = m_txopLimitsForSta.contains(AC_BE) ? m_txopLimitsForSta.at(AC_BE).at(linkId)
+                                                   : edca->GetTxopLimit(linkId);
     edcaParameters.SetBeTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
 
     edca = GetQosTxop(AC_BK);
-    txopLimit = edca->GetTxopLimit(linkId);
     edcaParameters.SetBkAci(1);
-    edcaParameters.SetBkCWmin(edca->GetMinCw(linkId));
-    edcaParameters.SetBkCWmax(edca->GetMaxCw(linkId));
-    edcaParameters.SetBkAifsn(edca->GetAifsn(linkId));
+    edcaParameters.SetBkCWmin(m_cwMinsForSta.contains(AC_BK) ? m_cwMinsForSta.at(AC_BK).at(linkId)
+                                                             : edca->GetMinCw(linkId));
+    edcaParameters.SetBkCWmax(m_cwMaxsForSta.contains(AC_BK) ? m_cwMaxsForSta.at(AC_BK).at(linkId)
+                                                             : edca->GetMaxCw(linkId));
+    edcaParameters.SetBkAifsn(m_aifsnsForSta.contains(AC_BK) ? m_aifsnsForSta.at(AC_BK).at(linkId)
+                                                             : edca->GetAifsn(linkId));
+    txopLimit = m_txopLimitsForSta.contains(AC_BK) ? m_txopLimitsForSta.at(AC_BK).at(linkId)
+                                                   : edca->GetTxopLimit(linkId);
     edcaParameters.SetBkTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
 
     edca = GetQosTxop(AC_VI);
-    txopLimit = edca->GetTxopLimit(linkId);
     edcaParameters.SetViAci(2);
-    edcaParameters.SetViCWmin(edca->GetMinCw(linkId));
-    edcaParameters.SetViCWmax(edca->GetMaxCw(linkId));
-    edcaParameters.SetViAifsn(edca->GetAifsn(linkId));
+    edcaParameters.SetViCWmin(m_cwMinsForSta.contains(AC_VI) ? m_cwMinsForSta.at(AC_VI).at(linkId)
+                                                             : edca->GetMinCw(linkId));
+    edcaParameters.SetViCWmax(m_cwMaxsForSta.contains(AC_VI) ? m_cwMaxsForSta.at(AC_VI).at(linkId)
+                                                             : edca->GetMaxCw(linkId));
+    edcaParameters.SetViAifsn(m_aifsnsForSta.contains(AC_VI) ? m_aifsnsForSta.at(AC_VI).at(linkId)
+                                                             : edca->GetAifsn(linkId));
+    txopLimit = m_txopLimitsForSta.contains(AC_VI) ? m_txopLimitsForSta.at(AC_VI).at(linkId)
+                                                   : edca->GetTxopLimit(linkId);
     edcaParameters.SetViTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
 
     edca = GetQosTxop(AC_VO);
-    txopLimit = edca->GetTxopLimit(linkId);
     edcaParameters.SetVoAci(3);
-    edcaParameters.SetVoCWmin(edca->GetMinCw(linkId));
-    edcaParameters.SetVoCWmax(edca->GetMaxCw(linkId));
-    edcaParameters.SetVoAifsn(edca->GetAifsn(linkId));
+    edcaParameters.SetVoCWmin(m_cwMinsForSta.contains(AC_VO) ? m_cwMinsForSta.at(AC_VO).at(linkId)
+                                                             : edca->GetMinCw(linkId));
+    edcaParameters.SetVoCWmax(m_cwMaxsForSta.contains(AC_VO) ? m_cwMaxsForSta.at(AC_VO).at(linkId)
+                                                             : edca->GetMaxCw(linkId));
+    edcaParameters.SetVoAifsn(m_aifsnsForSta.contains(AC_VO) ? m_aifsnsForSta.at(AC_VO).at(linkId)
+                                                             : edca->GetAifsn(linkId));
+    txopLimit = m_txopLimitsForSta.contains(AC_VO) ? m_txopLimitsForSta.at(AC_VO).at(linkId)
+                                                   : edca->GetTxopLimit(linkId);
     edcaParameters.SetVoTxopLimit(static_cast<uint16_t>(txopLimit.GetMicroSeconds() / 32));
 
     edcaParameters.SetQosInfo(0);
@@ -721,7 +844,7 @@
         mldCapabilities->srsSupport = 0;
         EnumValue<WifiTidToLinkMappingNegSupport> negSupport;
         ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
-        mldCapabilities->tidToLinkMappingSupport = negSupport.Get();
+        mldCapabilities->tidToLinkMappingSupport = static_cast<uint8_t>(negSupport.Get());
         mldCapabilities->freqSepForStrApMld = 0; // not supported yet
         mldCapabilities->aarSupport = 0;         // not supported yet
     }
@@ -768,7 +891,7 @@
 ApWifiMac::GetHtOperation(uint8_t linkId) const
 {
     NS_LOG_FUNCTION(this << +linkId);
-    NS_ASSERT(GetHtSupported());
+    NS_ASSERT(GetHtSupported(linkId));
     HtOperation operation;
     auto phy = GetWifiPhy(linkId);
     auto remoteStationManager = GetWifiRemoteStationManager(linkId);
@@ -809,7 +932,8 @@
     uint8_t nMcs = mcsList.size();
     for (const auto& sta : GetLink(linkId).staList)
     {
-        if (remoteStationManager->GetHtSupported(sta.second))
+        if (remoteStationManager->GetHtSupported(sta.second) ||
+            remoteStationManager->GetStationHe6GhzCapabilities(sta.second))
         {
             uint64_t maxSupportedRateByHtSta = 0; // in bit/s
             auto itMcs = mcsList.begin();
@@ -936,7 +1060,22 @@
             nss,
             11); // TBD: hardcode to 11 for now since we assume all MCS values are supported
     }
-    operation.SetBssColor(GetHeConfiguration()->GetBssColor());
+    operation.m_bssColorInfo.m_bssColor = GetHeConfiguration()->GetBssColor();
+
+    if (auto phy = GetWifiPhy(linkId); phy && phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ)
+    {
+        HeOperation::OpInfo6GHz op6Ghz;
+        const auto bw = phy->GetChannelWidth();
+        const auto ch = phy->GetOperatingChannel();
+        op6Ghz.m_chWid = (bw == 20) ? 0 : (bw == 40) ? 1 : (bw == 80) ? 2 : 3;
+        op6Ghz.m_primCh = ch.GetPrimaryChannelNumber(20, WIFI_STANDARD_80211ax);
+        op6Ghz.m_chCntrFreqSeg0 =
+            (bw == 160) ? ch.GetPrimaryChannelNumber(80, WIFI_STANDARD_80211ax) : ch.GetNumber();
+        // TODO: for 80+80 MHz channels, set this field to the secondary 80 MHz segment number
+        op6Ghz.m_chCntrFreqSeg1 = (bw == 160) ? ch.GetNumber() : 0;
+
+        operation.m_6GHzOpInfo = op6Ghz;
+    }
 
     return operation;
 }
@@ -1000,7 +1139,7 @@
     {
         probe.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
     }
-    if (GetHtSupported())
+    if (GetHtSupported(linkId))
     {
         probe.Get<ExtendedCapabilities>() = GetExtendedCapabilities();
         probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
@@ -1015,10 +1154,14 @@
     {
         probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
         probe.Get<HeOperation>() = GetHeOperation(linkId);
-        if (auto muEdcaParameterSet = GetMuEdcaParameterSet(); muEdcaParameterSet.has_value())
+        if (auto muEdcaParameterSet = GetMuEdcaParameterSet())
         {
             probe.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
         }
+        if (Is6GhzBand(linkId))
+        {
+            probe.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
+        }
     }
     if (GetEhtSupported())
     {
@@ -1099,7 +1242,7 @@
     {
         assoc.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
     }
-    if (GetHtSupported())
+    if (GetHtSupported(linkId))
     {
         assoc.Get<ExtendedCapabilities>() = GetExtendedCapabilities();
         assoc.Get<HtCapabilities>() = GetHtCapabilities(linkId);
@@ -1118,6 +1261,10 @@
         {
             assoc.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
         }
+        if (Is6GhzBand(linkId))
+        {
+            assoc.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
+        }
     }
     if (GetEhtSupported())
     {
@@ -1266,7 +1413,8 @@
                 {
                     link.numNonErpStations++;
                 }
-                if (!remoteStationManager->GetHtSupported(staAddr))
+                if (!remoteStationManager->GetHtSupported(staAddr) &&
+                    !remoteStationManager->GetStationHe6GhzCapabilities(staAddr))
                 {
                     link.numNonHtStations++;
                 }
@@ -1391,7 +1539,7 @@
     {
         beacon.Get<EdcaParameterSet>() = GetEdcaParameterSet(linkId);
     }
-    if (GetHtSupported())
+    if (GetHtSupported(linkId))
     {
         beacon.Get<ExtendedCapabilities>() = GetExtendedCapabilities();
         beacon.Get<HtCapabilities>() = GetHtCapabilities(linkId);
@@ -1410,6 +1558,10 @@
         {
             beacon.Get<MuEdcaParameterSet>() = std::move(*muEdcaParameterSet);
         }
+        if (Is6GhzBand(linkId))
+        {
+            beacon.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
+        }
     }
     if (GetEhtSupported())
     {
@@ -1442,11 +1594,14 @@
     }
     packet->AddHeader(beacon);
 
+    NS_LOG_INFO("Generating beacon from " << link.feManager->GetAddress() << " linkID " << +linkId);
     // The beacon has it's own special queue, so we load it in there
     m_beaconTxop->Queue(packet, hdr);
     link.beaconEvent =
         Simulator::Schedule(GetBeaconInterval(), &ApWifiMac::SendOneBeacon, this, linkId);
 
+    ScheduleFilsDiscOrUnsolProbeRespFrames(linkId);
+
     // If a STA that does not support Short Slot Time associates,
     // the AP shall use long slot time beginning at the first Beacon
     // subsequent to the association of the long slot time STA.
@@ -1465,6 +1620,76 @@
     }
 }
 
+Ptr<WifiMpdu>
+ApWifiMac::GetFilsDiscovery(uint8_t linkId) const
+{
+    WifiMacHeader hdr(WIFI_MAC_MGT_ACTION);
+    hdr.SetAddr1(Mac48Address::GetBroadcast());
+    auto& link = GetLink(linkId);
+    hdr.SetAddr2(link.feManager->GetAddress());
+    hdr.SetAddr3(link.feManager->GetAddress());
+    hdr.SetDsNotFrom();
+    hdr.SetDsNotTo();
+
+    WifiActionHeader actionHdr;
+    WifiActionHeader::ActionValue action;
+    action.publicAction = WifiActionHeader::FILS_DISCOVERY;
+    actionHdr.SetAction(WifiActionHeader::PUBLIC, action);
+
+    FilsDiscHeader fils;
+    fils.SetSsid(GetSsid().PeekString());
+    fils.m_beaconInt = (m_beaconInterval / WIFI_TU).GetHigh();
+
+    fils.m_fdCap = FilsDiscHeader::FdCapability{};
+    fils.m_fdCap->SetOpChannelWidth(link.phy->GetChannelWidth());
+    fils.m_fdCap->SetMaxNss(std::min(link.phy->GetMaxSupportedTxSpatialStreams(),
+                                     link.phy->GetMaxSupportedRxSpatialStreams()));
+    fils.m_fdCap->SetStandard(link.phy->GetStandard());
+
+    fils.SetLengthSubfield();
+    fils.m_rnr = GetReducedNeighborReport(linkId);
+
+    auto packet = Create<Packet>();
+    packet->AddHeader(fils);
+    packet->AddHeader(actionHdr);
+
+    return Create<WifiMpdu>(packet, hdr);
+}
+
+void
+ApWifiMac::ScheduleFilsDiscOrUnsolProbeRespFrames(uint8_t linkId)
+{
+    NS_LOG_FUNCTION(this << linkId);
+    auto phy = GetLink(linkId).phy;
+
+    auto fdBeaconInterval = (phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ) ? m_fdBeaconInterval6GHz
+                                                                      : m_fdBeaconIntervalNon6GHz;
+
+    if (!fdBeaconInterval.IsStrictlyPositive())
+    {
+        NS_LOG_DEBUG("Sending FILS Discovery/unsolicited Probe Response disabled");
+        return;
+    }
+
+    // Schedule FD or unsolicited Probe Response frames (IEEE Std 802.11ax-2021 26.17.2.3.2)
+    for (uint8_t count = 1; count < (m_beaconInterval / fdBeaconInterval).GetHigh(); ++count)
+    {
+        if (m_sendUnsolProbeResp)
+        {
+            Simulator::Schedule(fdBeaconInterval * count,
+                                &ApWifiMac::SendProbeResp,
+                                this,
+                                Mac48Address::GetBroadcast(),
+                                linkId);
+        }
+        else
+        {
+            Simulator::Schedule(fdBeaconInterval * count,
+                                [=, this]() { m_beaconTxop->Queue(GetFilsDiscovery(linkId)); });
+        }
+    }
+}
+
 void
 ApWifiMac::TxOk(Ptr<const WifiMpdu> mpdu)
 {
@@ -1526,7 +1751,7 @@
             // we can stop the timer and enforce the configuration deriving from the
             // EML Notification frame sent by the EMLSR client
             if (auto eventIt = m_transitionTimeoutEvents.find(hdr.GetAddr1());
-                eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsRunning())
+                eventIt != m_transitionTimeoutEvents.cend() && eventIt->second.IsPending())
             {
                 // no need to wait until the expiration of the transition timeout
                 eventIt->second.PeekEventImpl()->Invoke();
@@ -1726,12 +1951,14 @@
                 ForwardUp(packet, from, to);
             }
         }
+        // NOLINTBEGIN(bugprone-branch-clone)
         else if (hdr->IsFromDs() && hdr->IsToDs())
         {
             // this is an AP-to-AP frame
             // we ignore for now.
             NotifyRxDrop(packet);
         }
+        // NOLINTEND(bugprone-branch-clone)
         else
         {
             // we can ignore these frames since
@@ -1816,7 +2043,9 @@
                         {
                             GetLink(linkId).numNonErpStations--;
                         }
-                        if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from))
+                        if (!GetWifiRemoteStationManager(linkId)->GetHtSupported(from) &&
+                            !GetWifiRemoteStationManager(linkId)->GetStationHe6GhzCapabilities(
+                                from))
                         {
                             GetLink(linkId).numNonHtStations--;
                         }
@@ -1888,7 +2117,7 @@
             return failure("STA's supported rate set not compatible with our Basic Rate set");
         }
 
-        if (GetHtSupported())
+        if (GetHtSupported(linkId))
         {
             // check whether the HT STA supports all MCSs in Basic MCS Set
             const auto& htCapabilities = frame.template Get<HtCapabilities>();
@@ -1935,6 +2164,13 @@
                     }
                 }
             }
+            if (Is6GhzBand(linkId))
+            {
+                if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
+                {
+                    remoteStationManager->AddStationHe6GhzCapabilities(from, *he6GhzCapabilities);
+                }
+            }
         }
         if (GetEhtSupported())
         {
@@ -1981,7 +2217,7 @@
                 EnumValue<WifiTidToLinkMappingNegSupport> negSupport;
                 ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
 
-                if (negSupport.Get() == 0)
+                if (negSupport.Get() == WifiTidToLinkMappingNegSupport::NOT_SUPPORTED)
                 {
                     return failure("TID-to-Link Mapping negotiation not supported");
                 }
@@ -2019,7 +2255,7 @@
                     break;
                 }
 
-                if (negSupport.Get() == 1 &&
+                if (negSupport.Get() == WifiTidToLinkMappingNegSupport::SAME_LINK_SET &&
                     !TidToLinkMappingValidForNegType1(dlMapping, ulMapping))
                 {
                     return failure("Mapping TIDs to distinct link sets is incompatible with "
@@ -2055,7 +2291,7 @@
         {
             remoteStationManager->AddSupportedErpSlotTime(from, true);
         }
-        if (GetHtSupported())
+        if (GetHtSupported(linkId))
         {
             const auto& htCapabilities = frame.template Get<HtCapabilities>();
             if (htCapabilities.has_value() && htCapabilities->IsSupportedMcs(0))
@@ -2378,7 +2614,7 @@
     {
         if (std::all_of(linkIds.begin(), linkIds.end(), [&](auto&& linkId) {
                 auto& staList = GetLink(linkId).staList;
-                return staList.find(nextAid) == staList.end();
+                return !staList.contains(nextAid);
             }))
         {
             return nextAid;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/ap-wifi-mac.h ns-3.42/src/wifi/model/ap-wifi-mac.h
--- ns-3.41/src/wifi/model/ap-wifi-mac.h	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/ap-wifi-mac.h	2024-05-29 15:29:47.196073800 -0700
@@ -25,6 +25,10 @@
 #include "wifi-mac-header.h"
 #include "wifi-mac.h"
 
+#include "ns3/attribute-container.h"
+#include "ns3/enum.h"
+#include "ns3/pair.h"
+
 #include <unordered_map>
 #include <variant>
 
@@ -59,7 +63,11 @@
  * \ingroup wifi
  *
  * Handle association, dis-association and authentication,
- * of STAs within an infrastructure BSS.
+ * of STAs within an infrastructure BSS.  By default, beacons are
+ * sent with PIFS access, zero backoff, and are generated roughly
+ * every 102.4 ms by default (configurable by an attribute) and
+ * with some jitter to de-synchronize beacon transmissions in
+ * multi-BSS scenarios.
  */
 class ApWifiMac : public WifiMac
 {
@@ -79,7 +87,7 @@
     void Enqueue(Ptr<Packet> packet, Mac48Address to, Mac48Address from) override;
     bool SupportsSendFrom() const override;
     Ptr<WifiMacQueue> GetTxopQueue(AcIndex ac) const override;
-    void ConfigureStandard(WifiStandard standard) override;
+    int64_t AssignStreams(int64_t stream) override;
 
     /**
      * \param interval the interval between two beacon transmissions.
@@ -91,17 +99,6 @@
     Time GetBeaconInterval() const;
 
     /**
-     * Assign a fixed random variable stream number to the random variables
-     * used by this model.  Return the number of streams (possibly zero) that
-     * have been assigned.
-     *
-     * \param stream first stream index to use
-     *
-     * \return the number of stream indices assigned by this model
-     */
-    int64_t AssignStreams(int64_t stream);
-
-    /**
      * Get a const reference to the map of associated stations on the given link.
      * Each station is specified by an (association ID, MAC address) pair. Make sure
      * not to use the returned reference after that this object has been deallocated.
@@ -171,6 +168,65 @@
      */
     uint8_t GetMaxBufferStatus(Mac48Address address) const;
 
+    /// ACI-indexed map of access parameters of type unsigned integer (CWmin, CWmax and AIFSN)
+    using UintAccessParamsMap = std::map<AcIndex, std::vector<uint64_t>>;
+
+    /// ACI-indexed map of access parameters of type Time (TxopLimit)
+    using TimeAccessParamsMap = std::map<AcIndex, std::vector<Time>>;
+
+    /// AttributeValue type of a pair (ACI, access parameters of type unsigned integer)
+    using UintAccessParamsPairValue =
+        PairValue<EnumValue<AcIndex>, AttributeContainerValue<UintegerValue, ',', std::vector>>;
+
+    /// AttributeValue type of a pair (ACI, access parameters of type Time)
+    using TimeAccessParamsPairValue =
+        PairValue<EnumValue<AcIndex>, AttributeContainerValue<TimeValue, ',', std::vector>>;
+
+    /// AttributeValue type of an ACI-indexed map of access parameters of type unsigned integer
+    using UintAccessParamsMapValue = AttributeContainerValue<UintAccessParamsPairValue, ';'>;
+
+    /// AttributeValue type of ACI-indexed map of access parameters of type Time
+    using TimeAccessParamsMapValue = AttributeContainerValue<TimeAccessParamsPairValue, ';'>;
+
+    /**
+     * Get a checker for the CwMinsForSta, CwMaxsForSta and AifsnsForSta attributes, which can
+     * be used to deserialize an ACI-indexed map of access parameters of type unsigned integer
+     * (CWmin, CWmax and AIFSN) from a string:
+     *
+     * \code
+     *   ApWifiMac::UintAccessParamsMapValue value;
+     *   value.DeserializeFromString("BE 31,31; VO 15,15",
+     *                               ApWifiMac::GetUintAccessParamsChecker<uint32_t>());
+     *   auto map = value.Get();
+     * \endcode
+     *
+     * The type of \p map is ApWifiMac::UintAccessParamsMapValue::result_type, which is
+     * std::list<std::pair<AcIndex, std::vector<uint64_t>>>.
+     *
+     * \tparam T \explicit the type of the unsigned integer access parameter
+     * \return a checker for the CwMinsForSta, CwMaxsForSta and AifsnsForSta attributes
+     */
+    template <class T>
+    static Ptr<const AttributeChecker> GetUintAccessParamsChecker();
+
+    /**
+     * Get a checker for the TxopLimitsForSta attribute, which can be used to deserialize an
+     * ACI-indexed map of access parameters of type Time (TxopLimit) from a string:
+     *
+     * \code
+     *   ApWifiMac::TimeAccessParamsMapValue value;
+     *   value.DeserializeFromString("BE 3200us; VO 3232us",
+     *                               ApWifiMac::GetTimeAccessParamsChecker());
+     *   auto map = value.Get();
+     * \endcode
+     *
+     * The type of \p map is ApWifiMac::TimeAccessParamsMapValue::result_type, which is
+     * std::list<std::pair<AcIndex, std::vector<Time>>>.
+     *
+     * \return a checker for the TxopLimitsForSta attribute
+     */
+    static Ptr<const AttributeChecker> GetTimeAccessParamsChecker();
+
   protected:
     /**
      * Structure holding information specific to a single link. Here, the meaning of
@@ -209,6 +265,7 @@
     std::unique_ptr<LinkEntity> CreateLinkEntity() const override;
     Mac48Address DoGetLocalAddress(const Mac48Address& remoteAddr) const override;
     void Receive(Ptr<const WifiMpdu> mpdu, uint8_t linkId) override;
+    void DoCompleteConfig() override;
 
     /**
      * Check whether the supported rate set included in the received (Re)Association
@@ -356,6 +413,22 @@
     void SendOneBeacon(uint8_t linkId);
 
     /**
+     * Get the FILS Discovery frame to send on the given link.
+     *
+     * \param linkId the ID of the given link
+     * \return the FILS Discovery frame to send on the given link
+     */
+    Ptr<WifiMpdu> GetFilsDiscovery(uint8_t linkId) const;
+
+    /**
+     * Schedule the transmission of FILS Discovery frames or unsolicited Probe Response frames
+     * on the given link
+     *
+     * \param linkId the ID of the given link
+     */
+    void ScheduleFilsDiscOrUnsolProbeRespFrames(uint8_t linkId);
+
+    /**
      * Process the Power Management bit in the Frame Control field of an MPDU
      * successfully received on the given link.
      *
@@ -528,6 +601,17 @@
     /// transition timeout events running for EMLSR clients
     std::map<Mac48Address, EventId> m_transitionTimeoutEvents;
 
+    UintAccessParamsMap m_cwMinsForSta;     //!< Per-AC CW min values to advertise to stations
+    UintAccessParamsMap m_cwMaxsForSta;     //!< Per-AC CW max values to advertise to stations
+    UintAccessParamsMap m_aifsnsForSta;     //!< Per-AC AIFS values to advertise to stations
+    TimeAccessParamsMap m_txopLimitsForSta; //!< Per-AC TXOP limits values to advertise to stations
+
+    Time m_fdBeaconInterval6GHz;    //!< Time elapsing between a beacon and FILS Discovery (FD)
+                                    //!< frame or between two FD frames on 6GHz links
+    Time m_fdBeaconIntervalNon6GHz; //!< Time elapsing between a beacon and FILS Discovery (FD)
+                                    //!< frame or between two FD frames on 2.4GHz and 5GHz links
+    bool m_sendUnsolProbeResp;      //!< send unsolicited Probe Response instead of FILS Discovery
+
     /// store value and timestamp for each Buffer Status Report
     struct BsrType
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/block-ack-manager.cc ns-3.42/src/wifi/model/block-ack-manager.cc
--- ns-3.41/src/wifi/model/block-ack-manager.cc	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/block-ack-manager.cc	2024-05-29 15:29:47.196073800 -0700
@@ -99,11 +99,11 @@
 
 void
 BlockAckManager::CreateOriginatorAgreement(const MgtAddBaRequestHeader& reqHdr,
-                                           const Mac48Address& recipient,
-                                           bool htSupported)
+                                           const Mac48Address& recipient)
 {
-    NS_LOG_FUNCTION(this << reqHdr << recipient << htSupported);
-    const uint8_t tid = reqHdr.GetTid();
+    NS_LOG_FUNCTION(this << reqHdr << recipient);
+    const auto tid = reqHdr.GetTid();
+
     OriginatorBlockAckAgreement agreement(recipient, tid);
     agreement.SetStartingSequence(reqHdr.GetStartingSequence());
     /* For now we assume that originator doesn't use this field. Use of this field
@@ -111,7 +111,7 @@
     agreement.SetBufferSize(reqHdr.GetBufferSize());
     agreement.SetTimeout(reqHdr.GetTimeout());
     agreement.SetAmsduSupport(reqHdr.IsAmsduSupported());
-    agreement.SetHtSupported(htSupported);
+    agreement.SetHtSupported(true);
     if (reqHdr.IsImmediateBlockAck())
     {
         agreement.SetImmediateBlockAck();
@@ -195,11 +195,10 @@
 BlockAckManager::CreateRecipientAgreement(const MgtAddBaResponseHeader& respHdr,
                                           const Mac48Address& originator,
                                           uint16_t startingSeq,
-                                          bool htSupported,
                                           Ptr<MacRxMiddle> rxMiddle)
 {
-    NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << htSupported << rxMiddle);
-    uint8_t tid = respHdr.GetTid();
+    NS_LOG_FUNCTION(this << respHdr << originator << startingSeq << rxMiddle);
+    const auto tid = respHdr.GetTid();
 
     RecipientBlockAckAgreement agreement(originator,
                                          respHdr.IsAmsduSupported(),
@@ -207,7 +206,8 @@
                                          respHdr.GetBufferSize(),
                                          respHdr.GetTimeout(),
                                          startingSeq,
-                                         htSupported);
+                                         true);
+
     agreement.SetMacRxMiddle(rxMiddle);
     if (respHdr.IsImmediateBlockAck())
     {
@@ -450,7 +450,7 @@
     uint16_t nSuccessfulMpdus = 0;
     uint16_t nFailedMpdus = 0;
 
-    if (it->second.first.m_inactivityEvent.IsRunning())
+    if (it->second.first.m_inactivityEvent.IsPending())
     {
         /* Upon reception of a BlockAck frame, the inactivity timer at the
             originator must be reset.
@@ -532,7 +532,7 @@
     {
         // MPDUs that were transmitted on another link shall stay inflight
         auto linkIds = (*mpduIt)->GetInFlightLinkIds();
-        if (linkIds.count(linkId) == 0)
+        if (!linkIds.contains(linkId))
         {
             mpduIt = HandleInFlightMpdu(linkId, mpduIt, STAY_INFLIGHT, it, now);
             continue;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/block-ack-manager.h ns-3.42/src/wifi/model/block-ack-manager.h
--- ns-3.41/src/wifi/model/block-ack-manager.h	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/block-ack-manager.h	2024-05-29 15:29:47.196073800 -0700
@@ -106,14 +106,12 @@
     /**
      * \param reqHdr Relative Add block ack request (action frame).
      * \param recipient Address of peer station involved in block ack mechanism.
-     * \param htSupported Whether both originator and recipient support HT
      *
      * Creates a new originator block ack agreement in pending state. When a ADDBA response
      * with a successful status code is received, the relative agreement becomes established.
      */
     void CreateOriginatorAgreement(const MgtAddBaRequestHeader& reqHdr,
-                                   const Mac48Address& recipient,
-                                   bool htSupported = true);
+                                   const Mac48Address& recipient);
     /**
      * \param recipient Address of peer station involved in block ack mechanism.
      * \param tid traffic ID of transmitted packet.
@@ -140,7 +138,6 @@
      *        mechanism.
      * \param startingSeq Sequence number of the first MPDU of all
      *        packets for which block ack was negotiated.
-     * \param htSupported whether HT support is enabled
      * \param rxMiddle the MAC RX Middle on this station
      *
      * This function is typically invoked only by ns3::WifiMac
@@ -153,7 +150,6 @@
     void CreateRecipientAgreement(const MgtAddBaResponseHeader& respHdr,
                                   const Mac48Address& originator,
                                   uint16_t startingSeq,
-                                  bool htSupported,
                                   Ptr<MacRxMiddle> rxMiddle);
     /**
      * Destroy a recipient Block Ack agreement.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/channel-access-manager.cc ns-3.42/src/wifi/model/channel-access-manager.cc
--- ns-3.41/src/wifi/model/channel-access-manager.cc	2024-02-09 14:44:08.577794800 -0800
+++ ns-3.42/src/wifi/model/channel-access-manager.cc	2024-05-29 15:29:47.196073800 -0700
@@ -313,7 +313,7 @@
                                                uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << phy << channel << linkId);
-    NS_ASSERT_MSG(m_switchingEmlsrLinks.count(phy) == 0,
+    NS_ASSERT_MSG(!m_switchingEmlsrLinks.contains(phy),
                   "The given PHY is already expected to switch channel");
     m_switchingEmlsrLinks.emplace(phy, EmlsrLinkSwitchInfo{channel, linkId});
 }
@@ -733,7 +733,7 @@
     {
         NS_LOG_DEBUG("expected backoff end=" << expectedBackoffEnd);
         Time expectedBackoffDelay = expectedBackoffEnd - Simulator::Now();
-        if (m_accessTimeout.IsRunning() &&
+        if (m_accessTimeout.IsPending() &&
             Simulator::GetDelayLeft(m_accessTimeout) > expectedBackoffDelay)
         {
             m_accessTimeout.Cancel();
@@ -976,7 +976,7 @@
     InitLastBusyStructs();
 
     // Cancel timeout
-    if (m_accessTimeout.IsRunning())
+    if (m_accessTimeout.IsPending())
     {
         m_accessTimeout.Cancel();
     }
@@ -1015,7 +1015,7 @@
     NS_LOG_FUNCTION(this);
     m_sleeping = true;
     // Cancel timeout
-    if (m_accessTimeout.IsRunning())
+    if (m_accessTimeout.IsPending())
     {
         m_accessTimeout.Cancel();
     }
@@ -1033,7 +1033,7 @@
     NS_LOG_FUNCTION(this);
     m_off = true;
     // Cancel timeout
-    if (m_accessTimeout.IsRunning())
+    if (m_accessTimeout.IsPending())
     {
         m_accessTimeout.Cancel();
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/default-emlsr-manager.cc ns-3.42/src/wifi/model/eht/default-emlsr-manager.cc
--- ns-3.41/src/wifi/model/eht/default-emlsr-manager.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/default-emlsr-manager.cc	2024-05-29 15:29:47.196073800 -0700
@@ -19,6 +19,8 @@
 
 #include "default-emlsr-manager.h"
 
+#include "eht-frame-exchange-manager.h"
+
 #include "ns3/boolean.h"
 #include "ns3/channel-access-manager.h"
 #include "ns3/log.h"
@@ -161,13 +163,14 @@
         }
         else
         {
-            Simulator::Schedule(mainPhy->GetDelayUntilIdle(),
-                                &DefaultEmlsrManager::SwitchMainPhy,
-                                this,
-                                GetMainPhyId(),
-                                false,
-                                DONT_RESET_BACKOFF,
-                                REQUEST_ACCESS);
+            Simulator::Schedule(mainPhy->GetDelayUntilIdle(), [=, this]() {
+                // request the main PHY to switch back to the primary link only if in the meantime
+                // no TXOP started on another link (which will require the main PHY to switch link)
+                if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
+                {
+                    SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
+                }
+            });
         }
         return;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/eht-configuration.cc ns-3.42/src/wifi/model/eht/eht-configuration.cc
--- ns-3.41/src/wifi/model/eht/eht-configuration.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/eht-configuration.cc	2024-05-29 15:29:47.200073700 -0700
@@ -36,6 +36,21 @@
 
 NS_OBJECT_ENSURE_REGISTERED(EhtConfiguration);
 
+std::ostream&
+operator<<(std::ostream& os, WifiTidToLinkMappingNegSupport negsupport)
+{
+    switch (negsupport)
+    {
+    case WifiTidToLinkMappingNegSupport::NOT_SUPPORTED:
+        return os << "NOT_SUPPORTED";
+    case WifiTidToLinkMappingNegSupport::SAME_LINK_SET:
+        return os << "SAME_LINK_SET";
+    case WifiTidToLinkMappingNegSupport::ANY_LINK_SET:
+        return os << "ANY_LINK_SET";
+    };
+    return os << "UNKNOWN(" << static_cast<uint32_t>(negsupport) << ")";
+}
+
 EhtConfiguration::EhtConfiguration()
 {
     NS_LOG_FUNCTION(this);
@@ -94,19 +109,17 @@
                 UintegerValue(DEFAULT_MSD_MAX_N_TXOPS),
                 MakeUintegerAccessor(&EhtConfiguration::m_msdMaxNTxops),
                 MakeUintegerChecker<uint8_t>(0, 15))
-            .AddAttribute(
-                "TidToLinkMappingNegSupport",
-                "TID-to-Link Mapping Negotiation Support.",
-                EnumValue(WifiTidToLinkMappingNegSupport::WIFI_TID_TO_LINK_MAPPING_ANY_LINK_SET),
-                MakeEnumAccessor<WifiTidToLinkMappingNegSupport>(
-                    &EhtConfiguration::m_tidLinkMappingSupport),
-                MakeEnumChecker(
-                    WifiTidToLinkMappingNegSupport::WIFI_TID_TO_LINK_MAPPING_NOT_SUPPORTED,
-                    "NOT_SUPPORTED",
-                    WifiTidToLinkMappingNegSupport::WIFI_TID_TO_LINK_MAPPING_SAME_LINK_SET,
-                    "SAME_LINK_SET",
-                    WifiTidToLinkMappingNegSupport::WIFI_TID_TO_LINK_MAPPING_ANY_LINK_SET,
-                    "ANY_LINK_SET"))
+            .AddAttribute("TidToLinkMappingNegSupport",
+                          "TID-to-Link Mapping Negotiation Support.",
+                          EnumValue(WifiTidToLinkMappingNegSupport::ANY_LINK_SET),
+                          MakeEnumAccessor<WifiTidToLinkMappingNegSupport>(
+                              &EhtConfiguration::m_tidLinkMappingSupport),
+                          MakeEnumChecker(WifiTidToLinkMappingNegSupport::NOT_SUPPORTED,
+                                          "NOT_SUPPORTED",
+                                          WifiTidToLinkMappingNegSupport::SAME_LINK_SET,
+                                          "SAME_LINK_SET",
+                                          WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
+                                          "ANY_LINK_SET"))
             .AddAttribute(
                 "TidToLinkMappingDl",
                 "A list-of-TIDs-indexed map of the list of links where the TIDs are mapped to "
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/eht-configuration.h ns-3.42/src/wifi/model/eht/eht-configuration.h
--- ns-3.41/src/wifi/model/eht/eht-configuration.h	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/eht-configuration.h	2024-05-29 15:29:47.200073700 -0700
@@ -21,6 +21,7 @@
 #ifndef EHT_CONFIGURATION_H
 #define EHT_CONFIGURATION_H
 
+#include "ns3/deprecated.h"
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/wifi-utils.h"
@@ -43,13 +44,32 @@
 /**
  * \brief TID-to-Link Mapping Negotiation Support
  */
-enum WifiTidToLinkMappingNegSupport : uint8_t
+enum class WifiTidToLinkMappingNegSupport : uint8_t
 {
-    WIFI_TID_TO_LINK_MAPPING_NOT_SUPPORTED = 0,
-    WIFI_TID_TO_LINK_MAPPING_SAME_LINK_SET = 1,
-    WIFI_TID_TO_LINK_MAPPING_ANY_LINK_SET = 3
+    NOT_SUPPORTED = 0,
+    SAME_LINK_SET = 1,
+    ANY_LINK_SET = 3
 };
 
+NS_DEPRECATED_3_42("Use WifiTidToLinkMappingNegSupport::NOT_SUPPORTED instead")
+static constexpr auto WIFI_TID_TO_LINK_MAPPING_NOT_SUPPORTED = WifiTidToLinkMappingNegSupport::
+    NOT_SUPPORTED; //!< \deprecated See WifiTidToLinkMappingNegSupport::NOT_SUPPORTED
+NS_DEPRECATED_3_42("Use WifiTidToLinkMappingNegSupport::SAME_LINK_SET instead")
+static constexpr auto WIFI_TID_TO_LINK_MAPPING_SAME_LINK_SET = WifiTidToLinkMappingNegSupport::
+    SAME_LINK_SET; //!< \deprecated See WifiTidToLinkMappingNegSupport::SAME_LINK_SET
+NS_DEPRECATED_3_42("Use WifiTidToLinkMappingNegSupport::ANY_LINK_SET instead")
+static constexpr auto WIFI_TID_TO_LINK_MAPPING_ANY_LINK_SET =
+    WifiTidToLinkMappingNegSupport::ANY_LINK_SET; //!< \deprecated See
+                                                  //!< WifiTidToLinkMappingNegSupport::ANY_LINK_SET
+
+/**
+ * \brief Stream insertion operator.
+ * \param [in] os The reference to the output stream.
+ * \param [in] negsupport The WifiTidToLinkMappingNegSupport.
+ * \return The reference to the output stream.
+ */
+std::ostream& operator<<(std::ostream& os, WifiTidToLinkMappingNegSupport negsupport);
+
 /**
  * \brief EHT configuration
  * \ingroup wifi
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/eht-frame-exchange-manager.cc ns-3.42/src/wifi/model/eht/eht-frame-exchange-manager.cc
--- ns-3.41/src/wifi/model/eht/eht-frame-exchange-manager.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/eht-frame-exchange-manager.cc	2024-05-29 15:29:47.200073700 -0700
@@ -31,7 +31,7 @@
 #include "ns3/wifi-net-device.h"
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
@@ -177,6 +177,71 @@
 {
     NS_LOG_FUNCTION(this << edca << allowedWidth);
 
+    if (m_apMac)
+    {
+        for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
+        {
+            if (linkId == m_linkId)
+            {
+                continue;
+            }
+
+            // EMLSR clients involved in a DL or UL TXOP on another link
+            std::set<Mac48Address> emlsrClients;
+
+            // check if an EMLSR client is the holder of an UL TXOP on the other link
+            if (auto ehtFem =
+                    StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
+                ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
+                m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(
+                    ehtFem->m_txopHolder.value()))
+            {
+                emlsrClients.insert(ehtFem->m_txopHolder.value());
+            }
+
+            // check if EMLSR clients are involved in a DL TXOP on another link
+            for (const auto& address : m_protectedStas)
+            {
+                if (m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(address))
+                {
+                    emlsrClients.insert(address);
+                }
+            }
+
+            for (const auto& address : emlsrClients)
+            {
+                auto mldAddress =
+                    m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(address);
+                NS_ASSERT_MSG(mldAddress, "MLD address not found for " << address);
+
+                if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(*mldAddress))
+                {
+                    // EMLSR client did not enable EMLSR mode on this link, we can transmit to it
+                    continue;
+                }
+
+                // check that this link is blocked as expected
+                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddress, 0);
+                auto mask =
+                    m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, m_linkId);
+                NS_ASSERT_MSG(mask,
+                              "No mask for client " << *mldAddress << " on link " << +m_linkId);
+                if (!mask->test(
+                        static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
+                {
+                    NS_ASSERT_MSG(false,
+                                  "Transmissions to " << *mldAddress << " on link " << +m_linkId
+                                                      << " are not blocked");
+                    // in case asserts are disabled, block transmissions on the other links because
+                    // this is what we need
+                    m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                                 *mldAddress,
+                                                 {m_linkId});
+                }
+            }
+        }
+    }
+
     std::optional<Time> timeToCtsEnd;
 
     if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
@@ -286,6 +351,12 @@
         m_staMac->GetEmlsrManager()->NotifyUlTxopStart(m_linkId, timeToCtsEnd);
     }
 
+    if (started)
+    {
+        // we are starting a new TXOP, hence consider the previous ongoing TXOP as terminated
+        m_ongoingTxopEnd.Cancel();
+    }
+
     return started;
 }
 
@@ -394,10 +465,25 @@
 {
     NS_LOG_FUNCTION(this << address << delay.As(Time::US));
 
+    auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
+    NS_ASSERT_MSG(mldAddress, "MLD address not found for " << address);
+    NS_ASSERT_MSG(m_apMac, "This function shall only be called by AP MLDs");
+
+    for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
+    {
+        if (auto ehtFem =
+                StaticCast<EhtFrameExchangeManager>(m_mac->GetFrameExchangeManager(linkId));
+            ehtFem->m_ongoingTxopEnd.IsPending() && ehtFem->m_txopHolder &&
+            m_mac->GetWifiRemoteStationManager(linkId)->GetMldAddress(*ehtFem->m_txopHolder) ==
+                mldAddress)
+        {
+            // this EMLSR client is the holder of an UL TXOP, do not unblock links
+            return;
+        }
+    }
+
     // this EMLSR client switches back to listening operation a transition delay
     // after the given delay
-    auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
-    NS_ASSERT(mldAddress);
     auto emlCapabilities = GetWifiRemoteStationManager()->GetStationEmlCapabilities(address);
     NS_ASSERT(emlCapabilities);
 
@@ -577,6 +663,31 @@
 }
 
 void
+EhtFrameExchangeManager::SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr,
+                                           const CtrlTriggerHeader& trigger,
+                                           double muRtsSnr)
+{
+    NS_LOG_FUNCTION(this << muRtsHdr << trigger << muRtsSnr);
+
+    NS_ASSERT(m_staMac);
+    if (auto emlsrManager = m_staMac->GetEmlsrManager())
+    {
+        auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
+
+        // an aux PHY that is not TX capable may get a TXOP, release the channel and request
+        // the main PHY to switch channel. Shortly afterwards, the AP MLD may send an ICF, thus
+        // when the main PHY is scheduled to send the CTS, the main PHY may be switching channel
+        // or may be operating on another link
+        if (mainPhy->IsStateSwitching() || m_mac->GetLinkForPhy(mainPhy) != m_linkId)
+        {
+            NS_LOG_DEBUG("Main PHY is switching or operating on another link, abort sending CTS");
+            return;
+        }
+    }
+    HeFrameExchangeManager::SendCtsAfterMuRts(muRtsHdr, trigger, muRtsSnr);
+}
+
+void
 EhtFrameExchangeManager::CtsAfterMuRtsTimeout(Ptr<WifiMpdu> muRts, const WifiTxVector& txVector)
 {
     NS_LOG_FUNCTION(this << *muRts << txVector);
@@ -594,27 +705,73 @@
         auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(address);
         NS_ASSERT(mldAddress);
 
-        if (m_ongoingTxopEnd.IsRunning() && m_txopHolder &&
+        if (m_ongoingTxopEnd.IsPending() && m_txopHolder &&
             m_mac->GetMldAddress(*m_txopHolder) == mldAddress)
         {
             continue;
         }
 
+        std::set<uint8_t> linkIds;
         for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
         {
             if (linkId != m_linkId &&
                 m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
             {
-                m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
-                                               *mldAddress,
-                                               {linkId});
+                linkIds.insert(linkId);
             }
         }
+        m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                       *mldAddress,
+                                       linkIds);
     }
 
     HeFrameExchangeManager::CtsAfterMuRtsTimeout(muRts, txVector);
 }
 
+void
+EhtFrameExchangeManager::SendCtsAfterRts(const WifiMacHeader& rtsHdr,
+                                         WifiMode rtsTxMode,
+                                         double rtsSnr)
+{
+    NS_LOG_FUNCTION(this << rtsHdr << rtsTxMode << rtsSnr);
+
+    if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(rtsHdr.GetAddr2()))
+    {
+        // we are going to send a CTS to an EMLSR client, transmissions to such EMLSR client
+        // must be blocked on the other EMLSR links
+
+        auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(rtsHdr.GetAddr2());
+        NS_ASSERT_MSG(mldAddress, "MLD address not found for " << rtsHdr.GetAddr2());
+
+        for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
+        {
+            if (linkId != m_linkId &&
+                m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
+            {
+                // check that other links are blocked as expected
+                WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddress, 0);
+                auto mask =
+                    m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
+                NS_ASSERT_MSG(mask, "No mask for client " << *mldAddress << " on link " << +linkId);
+                if (!mask->test(
+                        static_cast<std::size_t>(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK)))
+                {
+                    NS_ASSERT_MSG(false,
+                                  "Transmissions to " << *mldAddress << " on link " << +linkId
+                                                      << " are not blocked");
+                    // in case asserts are disabled, block transmissions on the other links because
+                    // this is what we need
+                    m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                                 *mldAddress,
+                                                 {linkId});
+                }
+            }
+        }
+    }
+
+    HeFrameExchangeManager::SendCtsAfterRts(rtsHdr, rtsTxMode, rtsSnr);
+}
+
 bool
 EhtFrameExchangeManager::GetEmlsrSwitchToListening(Ptr<const WifiPsdu> psdu,
                                                    uint16_t aid,
@@ -732,16 +889,15 @@
     }
     else if (m_staMac && m_staMac->IsEmlsrLink(m_linkId))
     {
-        // notify the EMLSR Manager of the UL TXOP end, if the TXOP included the transmission of
-        // at least a frame
-        NS_ASSERT(m_staMac->GetEmlsrManager());
+        // Notify the UL TXOP end to the EMLSR Manager
         auto edca = DynamicCast<QosTxop>(txop);
         NS_ASSERT(edca);
-        if (auto txopStart = edca->GetTxopStartTime(m_linkId);
-            txopStart && Simulator::Now() > *txopStart)
-        {
-            m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
-        }
+        auto txopStart = edca->GetTxopStartTime(m_linkId);
+
+        NS_ASSERT(m_staMac->GetEmlsrManager());
+        m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId,
+                                                   (!txopStart || *txopStart == Simulator::Now()),
+                                                   m_ongoingTxopEnd.IsPending());
     }
 
     HeFrameExchangeManager::NotifyChannelReleased(txop);
@@ -780,7 +936,7 @@
             // is switching to listening operation by checking whether the AP is expecting a
             // response from it.
             if (GetWifiRemoteStationManager()->GetEmlsrEnabled(*clientIt) && !txVector.IsUlMu() &&
-                m_txTimer.GetStasExpectedToRespond().count(*clientIt) == 0)
+                !m_txTimer.GetStasExpectedToRespond().contains(*clientIt))
             {
                 EmlsrSwitchToListening(*clientIt, Seconds(0));
                 // this client is no longer involved in the current TXOP
@@ -806,23 +962,18 @@
     if (m_apMac && m_txopHolder == psdu->GetAddr2() &&
         GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
     {
-        if (!m_ongoingTxopEnd.IsRunning())
-        {
-            // an EMLSR client has started an UL TXOP. We may send a response after a SIFS or
-            // we may receive another frame after a SIFS. Postpone the TXOP end by considering
-            // the latter (which takes longer)
-            auto delay =
-                m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
-            NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
-            m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
-        }
-        else
+        if (!m_ongoingTxopEnd.IsPending())
         {
-            UpdateTxopEndOnRxEnd(psdu->GetDuration());
+            // an EMLSR client has started an UL TXOP. Start the ongoingTxopEnd timer so that
+            // the next call to UpdateTxopEndOnRxEnd does its job
+            m_ongoingTxopEnd =
+                Simulator::ScheduleNow(&EhtFrameExchangeManager::TxopEnd, this, m_txopHolder);
         }
+
+        UpdateTxopEndOnRxEnd(psdu->GetDuration());
     }
 
-    if (m_staMac && m_ongoingTxopEnd.IsRunning())
+    if (m_staMac && m_ongoingTxopEnd.IsPending())
     {
         if (GetEmlsrSwitchToListening(psdu, m_staMac->GetAssociationId(), m_self))
         {
@@ -837,6 +988,68 @@
     }
 }
 
+bool
+EhtFrameExchangeManager::CheckEmlsrClientStartingTxop(const WifiMacHeader& hdr,
+                                                      const WifiTxVector& txVector)
+{
+    NS_LOG_FUNCTION(this);
+
+    auto sender = hdr.GetAddr2();
+
+    if (m_ongoingTxopEnd.IsPending())
+    {
+        NS_LOG_DEBUG("A TXOP is already ongoing");
+        return false;
+    }
+
+    if (auto holder = FindTxopHolder(hdr, txVector); holder != sender)
+    {
+        NS_LOG_DEBUG("Sender (" << sender << ") differs from the TXOP holder ("
+                                << (holder ? Address(*holder) : Address()) << ")");
+        return false;
+    }
+
+    if (!GetWifiRemoteStationManager()->GetEmlsrEnabled(sender))
+    {
+        NS_LOG_DEBUG("Sender (" << sender << ") is not an EMLSR client");
+        return false;
+    }
+
+    NS_LOG_DEBUG("EMLSR client " << sender << " is starting a TXOP");
+
+    // Block transmissions for this EMLSR client on other links
+    auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(sender);
+    NS_ASSERT(mldAddress);
+
+    for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
+    {
+        if (linkId != m_linkId &&
+            m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
+        {
+            m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                         *mldAddress,
+                                         {linkId});
+        }
+    }
+
+    // Make sure that transmissions for this EMLSR client are not blocked on this link
+    // (the AP MLD may have sent an ICF on another link right before receiving this MPDU,
+    // thus transmissions on this link may have been blocked)
+    m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                                   *mldAddress,
+                                   {m_linkId});
+
+    // Stop the transition delay timer for this EMLSR client, if any is running
+    if (auto it = m_transDelayTimer.find(*mldAddress);
+        it != m_transDelayTimer.end() && it->second.IsPending())
+    {
+        it->second.PeekEventImpl()->Invoke();
+        it->second.Cancel();
+    }
+
+    return true;
+}
+
 void
 EhtFrameExchangeManager::ReceiveMpdu(Ptr<const WifiMpdu> mpdu,
                                      RxSignalInfo rxSignalInfo,
@@ -848,38 +1061,11 @@
 
     const auto& hdr = mpdu->GetHeader();
 
-    if (m_apMac && GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr2()))
+    if (m_apMac)
     {
-        // the AP MLD received an MPDU from an EMLSR client, which is now involved in an UL TXOP,
-        // hence block transmissions for this EMLSR client on other links
-        auto mldAddress = GetWifiRemoteStationManager()->GetMldAddress(hdr.GetAddr2());
-        NS_ASSERT(mldAddress);
-
-        for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); linkId++)
-        {
-            if (linkId != m_linkId &&
-                m_mac->GetWifiRemoteStationManager(linkId)->GetEmlsrEnabled(*mldAddress))
-            {
-                m_mac->BlockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
-                                             *mldAddress,
-                                             {linkId});
-            }
-        }
-
-        // Make sure that transmissions for this EMLSR client are not blocked on this link
-        // (the AP MLD may have sent an ICF on another link right before receiving this MPDU,
-        // thus transmissions on this link may have been blocked)
-        m_mac->UnblockUnicastTxOnLinks(WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
-                                       *mldAddress,
-                                       {m_linkId});
-
-        // Stop the transition delay timer for this EMLSR client, if any is running
-        if (auto it = m_transDelayTimer.find(*mldAddress);
-            it != m_transDelayTimer.end() && it->second.IsRunning())
-        {
-            it->second.PeekEventImpl()->Invoke();
-            it->second.Cancel();
-        }
+        // if the AP MLD received an MPDU from an EMLSR client that is starting an UL TXOP,
+        // block transmissions to the EMLSR client on other links
+        CheckEmlsrClientStartingTxop(hdr, txVector);
     }
 
     bool icfReceived = false;
@@ -916,16 +1102,11 @@
             }
 
             /**
-             * It might happen that the AP MLD has not yet received a data frame being transmitted
-             * by us on another link and starts sending an ICF on this link. The transmission of
-             * the ICF might be long enough to terminate after the subsequent acknowledgment, which
-             * terminates the TXOP on the other link. Consequently, no TXOP is ongoing when the
-             * reception of the ICF ends, hence the ICF is not dropped and a DL TXOP can start on
-             * this link. However, even if the aux PHY is able to receive the ICF, we need to allow
-             * enough time for the main PHY to switch to this link. Therefore, we assume that the
-             * ICF is successfully received (by an aux PHY) if the TXOP on the other link ended
-             * before the padding of the ICF. In order to determine when the TXOP ended, we can
-             * determine when the medium sync delay timer started on this link.
+             * It might happen that, while the aux PHY is receiving an ICF, the main PHY is
+             * completing a TXOP on another link or is returning to the primary link after a TXOP
+             * is completed on another link. In order to respond to the ICF, it is necessary that
+             * the main PHY has enough time to switch and be ready to operate on this link by the
+             * end of the ICF padding.
              *
              *                        TXOP end
              *                            │
@@ -935,28 +1116,32 @@
              *   EMLSR     │   QoS   │    │                            main PHY
              *   client    │  Data   │    │
              *             └─────────┘    │
-             *                            │- medium sync delay timer -│
              *                      ┌─────┬───┐                           this
              *   AP MLD             │ ICF │pad│                           link
              *  ────────────────────┴─────┴───┴───────────────────────────────────
              *                                                          aux PHY
              */
 
-            if (auto elapsed =
-                    m_staMac->GetEmlsrManager()->GetElapsedMediumSyncDelayTimer(m_linkId))
+            auto emlsrManager = m_staMac->GetEmlsrManager();
+            NS_ASSERT(emlsrManager);
+
+            if (auto mainPhy = m_staMac->GetDevice()->GetPhy(emlsrManager->GetMainPhyId());
+                mainPhy != m_phy)
             {
-                TimeValue padding;
-                m_staMac->GetEmlsrManager()->GetAttribute("EmlsrPaddingDelay", padding);
+                const auto delay = mainPhy->GetChannelSwitchDelay();
 
-                if (*elapsed < padding.Get())
+                if (mainPhy->GetState()->GetLastTime({WifiPhyState::TX,
+                                                      // WifiPhyState::RX, comment out for now
+                                                      WifiPhyState::SWITCHING,
+                                                      WifiPhyState::SLEEP}) >
+                    Simulator::Now() - delay)
                 {
                     NS_LOG_DEBUG("Drop ICF due to not enough time for the main PHY to switch link");
                     return;
                 }
             }
 
-            NS_ASSERT(m_staMac->GetEmlsrManager());
-            m_staMac->GetEmlsrManager()->NotifyIcfReceived(m_linkId);
+            emlsrManager->NotifyIcfReceived(m_linkId);
             icfReceived = true;
 
             // we just got involved in a DL TXOP. Check if we are still involved in the TXOP in a
@@ -965,7 +1150,8 @@
             NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + m_phy->GetSifs()).As(Time::S));
             m_ongoingTxopEnd = Simulator::Schedule(m_phy->GetSifs() + NanoSeconds(1),
                                                    &EhtFrameExchangeManager::TxopEnd,
-                                                   this);
+                                                   this,
+                                                   hdr.GetAddr2());
         }
     }
 
@@ -989,9 +1175,9 @@
 }
 
 void
-EhtFrameExchangeManager::TxopEnd()
+EhtFrameExchangeManager::TxopEnd(const std::optional<Mac48Address>& txopHolder)
 {
-    NS_LOG_FUNCTION(this);
+    NS_LOG_FUNCTION(this << txopHolder.has_value());
 
     if (m_phy->IsReceivingPhyHeader())
     {
@@ -1002,7 +1188,8 @@
         NS_LOG_DEBUG("PHY is decoding the PHY header of PPDU, postpone TXOP end");
         m_ongoingTxopEnd = Simulator::Schedule(MicroSeconds(WAIT_FOR_RXSTART_DELAY_USEC),
                                                &EhtFrameExchangeManager::TxopEnd,
-                                               this);
+                                               this,
+                                               txopHolder);
         return;
     }
 
@@ -1010,11 +1197,10 @@
     {
         m_staMac->GetEmlsrManager()->NotifyTxopEnd(m_linkId);
     }
-    else if (m_apMac && m_txopHolder &&
-             GetWifiRemoteStationManager()->GetEmlsrEnabled(*m_txopHolder))
+    else if (m_apMac && txopHolder && GetWifiRemoteStationManager()->GetEmlsrEnabled(*txopHolder))
     {
         // EMLSR client terminated its TXOP and is back to listening operation
-        EmlsrSwitchToListening(*m_txopHolder, Seconds(0));
+        EmlsrSwitchToListening(*txopHolder, Seconds(0));
     }
 }
 
@@ -1023,7 +1209,7 @@
 {
     NS_LOG_FUNCTION(this << txDuration.As(Time::MS) << durationId.As(Time::US));
 
-    if (!m_ongoingTxopEnd.IsRunning())
+    if (!m_ongoingTxopEnd.IsPending())
     {
         // nothing to do
         return;
@@ -1057,7 +1243,8 @@
     }
 
     NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
-    m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
+    m_ongoingTxopEnd =
+        Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this, m_txopHolder);
 }
 
 void
@@ -1065,7 +1252,7 @@
 {
     NS_LOG_FUNCTION(this << psduDuration.As(Time::MS));
 
-    if (!m_ongoingTxopEnd.IsRunning() || !psduDuration.IsStrictlyPositive())
+    if (!m_ongoingTxopEnd.IsPending() || !psduDuration.IsStrictlyPositive())
     {
         // nothing to do
         return;
@@ -1075,8 +1262,10 @@
     m_ongoingTxopEnd.Cancel();
 
     NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + psduDuration).As(Time::S));
-    m_ongoingTxopEnd =
-        Simulator::Schedule(psduDuration + NanoSeconds(1), &EhtFrameExchangeManager::TxopEnd, this);
+    m_ongoingTxopEnd = Simulator::Schedule(psduDuration + NanoSeconds(1),
+                                           &EhtFrameExchangeManager::TxopEnd,
+                                           this,
+                                           m_txopHolder);
 }
 
 void
@@ -1084,7 +1273,7 @@
 {
     NS_LOG_FUNCTION(this << durationId.As(Time::US));
 
-    if (!m_ongoingTxopEnd.IsRunning())
+    if (!m_ongoingTxopEnd.IsPending())
     {
         // nothing to do
         return;
@@ -1097,7 +1286,7 @@
     if (durationId <= m_phy->GetSifs())
     {
         NS_LOG_DEBUG("Assume TXOP ended based on Duration/ID value");
-        TxopEnd();
+        TxopEnd(m_txopHolder);
         return;
     }
 
@@ -1105,7 +1294,8 @@
     // Postpone the TXOP end by considering the latter (which takes longer)
     auto delay = m_phy->GetSifs() + m_phy->GetSlot() + MicroSeconds(RX_PHY_START_DELAY_USEC);
     NS_LOG_DEBUG("Expected TXOP end=" << (Simulator::Now() + delay).As(Time::S));
-    m_ongoingTxopEnd = Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this);
+    m_ongoingTxopEnd =
+        Simulator::Schedule(delay, &EhtFrameExchangeManager::TxopEnd, this, m_txopHolder);
 }
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/eht-frame-exchange-manager.h ns-3.42/src/wifi/model/eht/eht-frame-exchange-manager.h
--- ns-3.41/src/wifi/model/eht/eht-frame-exchange-manager.h	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/eht-frame-exchange-manager.h	2024-05-29 15:29:47.200073700 -0700
@@ -104,6 +104,9 @@
     void ForwardPsduMapDown(WifiConstPsduMap psduMap, WifiTxVector& txVector) override;
     void SendMuRts(const WifiTxParameters& txParams) override;
     void CtsAfterMuRtsTimeout(Ptr<WifiMpdu> muRts, const WifiTxVector& txVector) override;
+    void SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr,
+                           const CtrlTriggerHeader& trigger,
+                           double muRtsSnr) override;
     void TransmissionSucceeded() override;
     void TransmissionFailed() override;
     void NotifyChannelReleased(Ptr<Txop> txop) override;
@@ -115,6 +118,7 @@
                      bool inAmpdu) override;
     void NavResetTimeout() override;
     void IntraBssNavResetTimeout() override;
+    void SendCtsAfterRts(const WifiMacHeader& rtsHdr, WifiMode rtsTxMode, double rtsSnr) override;
 
     /**
      * This method is intended to be called when an AP MLD detects that an EMLSR client previously
@@ -130,6 +134,19 @@
 
   private:
     /**
+     * Check if the frame received (or being received) is sent by an EMLSR client to start an
+     * UL TXOP. If so, take the appropriate actions (e.g., block transmission to the EMLSR client
+     * on the other links). This method is intended to be called when an MPDU (possibly within
+     * an A-MPDU) is received or when the reception of the MAC header in an MPDU is notified.
+     *
+     * \param hdr the MAC header of the received (or being received) MPDU
+     * \param txVector the TXVECTOR used to transmit the frame received (or being received)
+     * \return whether the frame received (or being received) is sent by an EMLSR client to start
+     *         an UL TXOP
+     */
+    bool CheckEmlsrClientStartingTxop(const WifiMacHeader& hdr, const WifiTxVector& txVector);
+
+    /**
      * Update the TXOP end timer when starting a frame transmission.
      *
      * \param txDuration the TX duration of the frame being transmitted
@@ -153,8 +170,10 @@
 
     /**
      * Take actions when a TXOP (of which we are not the holder) ends.
+     *
+     * \param txopHolder the holder of the TXOP (if any)
      */
-    void TxopEnd();
+    void TxopEnd(const std::optional<Mac48Address>& txopHolder);
 
     EventId m_ongoingTxopEnd; //!< event indicating the possible end of the current TXOP (of which
                               //!< we are not the holder)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/eht-phy.cc ns-3.42/src/wifi/model/eht/eht-phy.cc
--- ns-3.41/src/wifi/model/eht/eht-phy.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/eht-phy.cc	2024-05-29 15:29:47.200073700 -0700
@@ -26,6 +26,9 @@
 #include "ns3/wifi-psdu.h"
 #include "ns3/wifi-utils.h"
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/eht-ppdu.cc ns-3.42/src/wifi/model/eht/eht-ppdu.cc
--- ns-3.41/src/wifi/model/eht/eht-ppdu.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/eht-ppdu.cc	2024-05-29 15:29:47.200073700 -0700
@@ -89,7 +89,7 @@
 WifiPpduType
 EhtPpdu::GetType() const
 {
-    if (m_psdus.count(SU_STA_ID) > 0)
+    if (m_psdus.contains(SU_STA_ID))
     {
         return WIFI_PPDU_TYPE_SU;
     }
@@ -108,13 +108,13 @@
 bool
 EhtPpdu::IsDlMu() const
 {
-    return (m_preamble == WIFI_PREAMBLE_EHT_MU) && (m_psdus.count(SU_STA_ID) == 0);
+    return (m_preamble == WIFI_PREAMBLE_EHT_MU) && !m_psdus.contains(SU_STA_ID);
 }
 
 bool
 EhtPpdu::IsUlMu() const
 {
-    return (m_preamble == WIFI_PREAMBLE_EHT_TB) && (m_psdus.count(SU_STA_ID) == 0);
+    return (m_preamble == WIFI_PREAMBLE_EHT_TB) && !m_psdus.contains(SU_STA_ID);
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/emlsr-manager.cc ns-3.42/src/wifi/model/eht/emlsr-manager.cc
--- ns-3.41/src/wifi/model/eht/emlsr-manager.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/emlsr-manager.cc	2024-05-29 15:29:47.200073700 -0700
@@ -31,6 +31,9 @@
 #include "ns3/wifi-net-device.h"
 #include "ns3/wifi-phy-state-helper.h"
 
+#include <iterator>
+#include <sstream>
+
 namespace ns3
 {
 
@@ -228,7 +231,7 @@
 EmlsrManager::GetElapsedMediumSyncDelayTimer(uint8_t linkId) const
 {
     if (const auto statusIt = m_mediumSyncDelayStatus.find(linkId);
-        statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
+        statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsPending())
     {
         return m_mediumSyncDuration - Simulator::GetDelayLeft(statusIt->second.timer);
     }
@@ -290,7 +293,12 @@
 void
 EmlsrManager::SetEmlsrLinks(const std::set<uint8_t>& linkIds)
 {
-    NS_LOG_FUNCTION(this);
+    std::stringstream ss;
+    if (g_log.IsEnabled(ns3::LOG_FUNCTION))
+    {
+        std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+    }
+    NS_LOG_FUNCTION(this << ss.str());
     NS_ABORT_MSG_IF(linkIds.size() == 1, "Cannot enable EMLSR mode on a single link");
 
     if (linkIds != m_emlsrLinks)
@@ -335,7 +343,7 @@
             action.protectedEhtAction ==
                 WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
         {
-            if (m_transitionTimeoutEvent.IsRunning())
+            if (m_transitionTimeoutEvent.IsPending())
             {
                 // no need to wait until the expiration of the transition timeout
                 m_transitionTimeoutEvent.PeekEventImpl()->Invoke();
@@ -413,7 +421,7 @@
     {
         auto stateHelper = m_staMac->GetWifiPhy(linkId)->GetState();
         NS_ASSERT(stateHelper);
-        NS_ASSERT_MSG(stateHelper->GetState() == TX,
+        NS_ASSERT_MSG(stateHelper->GetState() == WifiPhyState::TX,
                       "Expecting the aux PHY to be transmitting (an RTS frame)");
         NS_ASSERT_MSG(timeToCtsEnd.has_value(),
                       "Aux PHY is sending RTS, expected to get the time to CTS end");
@@ -426,22 +434,22 @@
 
         NS_ASSERT(delay.IsPositive());
         NS_LOG_DEBUG("Schedule main Phy switch in " << delay.As(Time::US));
-        Simulator::Schedule(delay,
-                            &EmlsrManager::SwitchMainPhy,
-                            this,
-                            linkId,
-                            false,
-                            RESET_BACKOFF,
-                            DONT_REQUEST_ACCESS);
+        m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay,
+                                                        &EmlsrManager::SwitchMainPhy,
+                                                        this,
+                                                        linkId,
+                                                        false,
+                                                        RESET_BACKOFF,
+                                                        DONT_REQUEST_ACCESS);
     }
 
     DoNotifyUlTxopStart(linkId);
 }
 
 void
-EmlsrManager::NotifyTxopEnd(uint8_t linkId)
+EmlsrManager::NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted, bool ongoingDlTxop)
 {
-    NS_LOG_FUNCTION(this << linkId);
+    NS_LOG_FUNCTION(this << linkId << ulTxopNotStarted << ongoingDlTxop);
 
     if (!m_staMac->IsEmlsrLink(linkId))
     {
@@ -449,18 +457,51 @@
         return;
     }
 
+    // If the main PHY has been scheduled to switch to this link, cancel the channel switch.
+    // This happens, e.g., when an aux PHY sent an RTS to start an UL TXOP but it did not
+    // receive a CTS response.
+    if (auto it = m_ulMainPhySwitch.find(linkId); it != m_ulMainPhySwitch.end())
+    {
+        if (it->second.IsPending())
+        {
+            NS_LOG_DEBUG("Cancelling main PHY channel switch event on link " << +linkId);
+            it->second.Cancel();
+        }
+        m_ulMainPhySwitch.erase(it);
+    }
+
+    // Unblock the other EMLSR links and start the MediumSyncDelay timer, provided that the TXOP
+    // included the transmission of at least a frame and there is no ongoing DL TXOP on this link.
+    // Indeed, the UL TXOP may have ended because the transmission of a frame failed and the
+    // corresponding TX timeout (leading to this call) may have occurred after the reception on
+    // this link of an ICF starting a DL TXOP. If the EMLSR Manager unblocked the other EMLSR
+    // links, another TXOP could be started on another EMLSR link (possibly leading to a crash)
+    // while the DL TXOP on this link is ongoing.
+    if (ongoingDlTxop)
+    {
+        NS_LOG_DEBUG("DL TXOP ongoing");
+        return;
+    }
+    if (ulTxopNotStarted)
+    {
+        NS_LOG_DEBUG("TXOP did not even start");
+        return;
+    }
+
     DoNotifyTxopEnd(linkId);
 
     Simulator::ScheduleNow([=, this]() {
         // unblock transmissions and resume medium access on other EMLSR links
+        std::set<uint8_t> linkIds;
         for (auto id : m_staMac->GetLinkIds())
         {
-            if (m_staMac->IsEmlsrLink(id))
+            if ((id != linkId) && m_staMac->IsEmlsrLink(id))
             {
-                m_staMac->UnblockTxOnLink(id, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
                 m_staMac->GetChannelAccessManager(id)->NotifyStopUsingOtherEmlsrLink();
+                linkIds.insert(id);
             }
         }
+        m_staMac->UnblockTxOnLink(linkIds, WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK);
 
         StartMediumSyncDelayTimer(linkId);
     });
@@ -474,7 +515,7 @@
     // if a MediumSyncDelay timer is running for the link on which the main PHY is going to
     // operate, set the CCA ED threshold to the MediumSyncDelay OFDM ED threshold
     if (auto statusIt = m_mediumSyncDelayStatus.find(linkId);
-        statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
+        statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsPending())
     {
         NS_LOG_DEBUG("Setting CCA ED threshold of PHY " << phy << " to " << +m_msdOfdmEdThreshold
                                                         << " on link " << +linkId);
@@ -508,6 +549,12 @@
     NS_ASSERT_MSG(mainPhy != m_staMac->GetWifiPhy(linkId),
                   "Main PHY is already operating on link " << +linkId);
 
+    if (mainPhy->IsStateSwitching())
+    {
+        NS_LOG_DEBUG("Main PHY is already switching, ignore new switching request");
+        return;
+    }
+
     // find the link on which the main PHY is operating
     auto currMainPhyLinkId = m_staMac->GetLinkForPhy(mainPhy);
     NS_ASSERT_MSG(currMainPhyLinkId, "Current link ID for main PHY not found");
@@ -526,11 +573,14 @@
                   "We should not ask the main PHY to switch channel while transmitting");
 
     // request the main PHY to switch channel
-    auto delay = mainPhy->GetChannelSwitchDelay();
-    NS_ASSERT_MSG(noSwitchDelay || delay <= m_lastAdvTransitionDelay,
-                  "Transition delay (" << m_lastAdvTransitionDelay.As(Time::US)
-                                       << ") should exceed the channel switch delay ("
-                                       << delay.As(Time::US) << ")");
+    const auto delay = mainPhy->GetChannelSwitchDelay();
+    const auto pifs = mainPhy->GetSifs() + mainPhy->GetSlot();
+    NS_ASSERT_MSG(noSwitchDelay || delay <= std::max(m_lastAdvTransitionDelay, pifs),
+                  "Channel switch delay ("
+                      << delay.As(Time::US)
+                      << ") should be shorter than the maximum between the Transition delay ("
+                      << m_lastAdvTransitionDelay.As(Time::US) << ") and a PIFS ("
+                      << pifs.As(Time::US) << ")");
     if (noSwitchDelay)
     {
         mainPhy->SetAttribute("ChannelSwitchDelay", TimeValue(Seconds(0)));
@@ -629,7 +679,7 @@
             // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS
             // is not received and the UL TXOP ends before the main PHY channel switch is
             // completed. The MSD timer is started on the link left "uncovered" by the main PHY
-            if (auto phy = m_staMac->GetWifiPhy(id); phy && !it->second.timer.IsRunning())
+            if (auto phy = m_staMac->GetWifiPhy(id); phy && !it->second.timer.IsPending())
             {
                 NS_LOG_DEBUG("Setting CCA ED threshold on link "
                              << +id << " to " << +m_msdOfdmEdThreshold << " PHY " << phy);
@@ -654,7 +704,7 @@
 
     auto timerIt = m_mediumSyncDelayStatus.find(linkId);
 
-    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
+    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
 
     timerIt->second.timer.Cancel();
     MediumSyncDelayTimerExpired(linkId);
@@ -667,7 +717,7 @@
 
     auto timerIt = m_mediumSyncDelayStatus.find(linkId);
 
-    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && !timerIt->second.timer.IsRunning());
+    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && !timerIt->second.timer.IsPending());
 
     // reset the MSD OFDM ED threshold
     auto phy = m_staMac->GetWifiPhy(linkId);
@@ -697,7 +747,7 @@
 
     const auto timerIt = m_mediumSyncDelayStatus.find(linkId);
 
-    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
+    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
     NS_ASSERT(timerIt->second.msdNTxopsLeft != 0);
 
     if (timerIt->second.msdNTxopsLeft)
@@ -713,7 +763,7 @@
 
     auto timerIt = m_mediumSyncDelayStatus.find(linkId);
 
-    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
+    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
     timerIt->second.msdNTxopsLeft.reset();
 }
 
@@ -724,7 +774,7 @@
 
     auto timerIt = m_mediumSyncDelayStatus.find(linkId);
 
-    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
+    NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsPending());
     return timerIt->second.msdNTxopsLeft == 0;
 }
 
@@ -916,19 +966,23 @@
         auto cam = m_staMac->GetChannelAccessManager(linkId);
         cam->NotifySwitchingEmlsrLink(auxPhy, channel, linkId);
 
-        void (WifiPhy::*fp)(const WifiPhyOperatingChannel&) = &WifiPhy::SetOperatingChannel;
-        Simulator::ScheduleNow(fp, auxPhy, channel);
+        auxPhy->SetOperatingChannel(channel);
 
         // the way the ChannelAccessManager handles EMLSR link switch implies that a PHY listener
         // is removed when the channel switch starts and another one is attached when the channel
-        // switch ends. In the meantime, no PHY is connected to the ChannelAccessManager. Inform
-        // the ChannelAccessManager that this channel switch is related to EMLSR operations, so
-        // that the ChannelAccessManager does not complain if events requiring access to the PHY
-        // occur during the channel switch.
-        cam->NotifyStartUsingOtherEmlsrLink();
-        Simulator::Schedule(auxPhy->GetChannelSwitchDelay(),
-                            &ChannelAccessManager::NotifyStopUsingOtherEmlsrLink,
-                            cam);
+        // switch ends. In the meantime, no PHY is connected to the ChannelAccessManager. Thus,
+        // reset all backoffs (so that access timeout is also cancelled) when the channel switch
+        // starts and request channel access (if needed) when the channel switch ends.
+        cam->ResetAllBackoffs();
+        Simulator::Schedule(auxPhy->GetChannelSwitchDelay(), [=, this]() {
+            for (const auto& [acIndex, ac] : wifiAcList)
+            {
+                m_staMac->GetQosTxop(acIndex)->StartAccessAfterEvent(
+                    linkId,
+                    Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
+                    Txop::CHECK_MEDIUM_BUSY);
+            }
+        });
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/eht/emlsr-manager.h ns-3.42/src/wifi/model/eht/emlsr-manager.h
--- ns-3.41/src/wifi/model/eht/emlsr-manager.h	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/eht/emlsr-manager.h	2024-05-29 15:29:47.200073700 -0700
@@ -187,8 +187,12 @@
      * Notify the end of a TXOP on the given link.
      *
      * \param linkId the ID of the given link
+     * \param ulTxopNotStarted whether this is a notification of the end of an UL TXOP that did
+     *                      not even start (no frame transmitted)
+     * \param ongoingDlTxop whether a DL TXOP is ongoing on the given link (if true, this is
+     *                      a notification of the end of an UL TXOP)
      */
-    void NotifyTxopEnd(uint8_t linkId);
+    void NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted = false, bool ongoingDlTxop = false);
 
     /**
      * Check whether the MediumSyncDelay timer is running for the STA operating on the given link.
@@ -472,6 +476,9 @@
         m_mainPhyChannels; //!< link ID-indexed map of operating channels for the main PHY
     std::map<uint8_t, WifiPhyOperatingChannel>
         m_auxPhyChannels; //!< link ID-indexed map of operating channels for the aux PHYs
+    std::map<uint8_t, EventId> m_ulMainPhySwitch; //!< link ID-indexed map of timers started when
+                                                  //!< an aux PHY gains an UL TXOP and schedules
+                                                  //!< a channel switch for the main PHY
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/frame-exchange-manager.cc ns-3.42/src/wifi/model/frame-exchange-manager.cc
--- ns-3.41/src/wifi/model/frame-exchange-manager.cc	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/frame-exchange-manager.cc	2024-05-29 15:29:47.200073700 -0700
@@ -29,7 +29,7 @@
 #include "ns3/log.h"
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
 
 // Time (in nanoseconds) to be added to the PSDU duration to yield the duration
 // of the timer that is started when the PHY indicates the start of the reception
@@ -73,7 +73,7 @@
 {
     NS_LOG_FUNCTION(this);
     m_txTimer.Cancel();
-    if (m_navResetEvent.IsRunning())
+    if (m_navResetEvent.IsPending())
     {
         m_navResetEvent.Cancel();
     }
@@ -273,7 +273,7 @@
     NS_LOG_FUNCTION(this << "PSDU reception started for " << psduDuration.As(Time::US)
                          << " (txVector: " << txVector << ")");
 
-    NS_ASSERT_MSG(!m_txTimer.IsRunning() || !m_navResetEvent.IsRunning(),
+    NS_ASSERT_MSG(!m_txTimer.IsRunning() || !m_navResetEvent.IsPending(),
                   "The TX timer and the NAV reset event cannot be both running");
 
     // No need to reschedule timeouts if PSDU duration is null. In this case,
@@ -288,7 +288,7 @@
         m_channelAccessManager->NotifyAckTimeoutResetNow();
     }
 
-    if (m_navResetEvent.IsRunning())
+    if (m_navResetEvent.IsPending())
     {
         m_navResetEvent.Cancel();
     }
@@ -347,10 +347,10 @@
     WifiTxParameters txParams;
     txParams.m_txVector =
         GetWifiRemoteStationManager()->GetDataTxVector(mpdu->GetHeader(), m_allowedWidth);
-    txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
-    txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
     txParams.AddMpdu(mpdu);
     UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
+    txParams.m_protection = m_protectionManager->TryAddMpdu(mpdu, txParams);
+    txParams.m_acknowledgment = m_ackManager->TryAddMpdu(mpdu, txParams);
 
     SendMpduWithProtection(mpdu, txParams);
 
@@ -401,7 +401,7 @@
     // and SendCtsToSelf() can reuse this value.
     NS_ASSERT(m_txParams.m_acknowledgment);
 
-    if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
+    if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
     {
         CalculateAcknowledgmentTime(m_txParams.m_acknowledgment.get());
     }
@@ -648,8 +648,8 @@
     NS_LOG_FUNCTION(this << header << size << &txParams << fragmentedPacket);
 
     NS_ASSERT(txParams.m_acknowledgment &&
-              txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
-    Time durationId = txParams.m_acknowledgment->acknowledgmentTime;
+              txParams.m_acknowledgment->acknowledgmentTime.has_value());
+    auto durationId = *txParams.m_acknowledgment->acknowledgmentTime;
 
     // if the current frame is a fragment followed by another fragment, we have to
     // update the Duration/ID to cover the next fragment and the corresponding Ack
@@ -705,10 +705,11 @@
     NS_ASSERT(txParams.m_protection && txParams.m_protection->method == WifiProtection::RTS_CTS);
     auto rtsCtsProtection = static_cast<WifiRtsCtsProtection*>(txParams.m_protection.get());
 
-    NS_ASSERT(txParams.m_txDuration != Time::Min());
+    NS_ASSERT(txParams.m_txDuration.has_value());
+    NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
     rts.SetDuration(GetRtsDurationId(rtsCtsProtection->rtsTxVector,
-                                     txParams.m_txDuration,
-                                     txParams.m_acknowledgment->acknowledgmentTime));
+                                     *txParams.m_txDuration,
+                                     *txParams.m_acknowledgment->acknowledgmentTime));
     Ptr<WifiMpdu> mpdu = Create<WifiMpdu>(Create<Packet>(), rts);
 
     // After transmitting an RTS frame, the STA shall wait for a CTSTimeout interval with
@@ -806,10 +807,11 @@
               txParams.m_protection->method == WifiProtection::CTS_TO_SELF);
     auto ctsToSelfProtection = static_cast<WifiCtsToSelfProtection*>(txParams.m_protection.get());
 
-    NS_ASSERT(txParams.m_txDuration != Time::Min());
+    NS_ASSERT(txParams.m_txDuration.has_value());
+    NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
     cts.SetDuration(GetCtsToSelfDurationId(ctsToSelfProtection->ctsTxVector,
-                                           txParams.m_txDuration,
-                                           txParams.m_acknowledgment->acknowledgmentTime));
+                                           *txParams.m_txDuration,
+                                           *txParams.m_acknowledgment->acknowledgmentTime));
 
     ForwardMpduDown(Create<WifiMpdu>(Create<Packet>(), cts), ctsToSelfProtection->ctsTxVector);
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/frame-exchange-manager.h ns-3.42/src/wifi/model/frame-exchange-manager.h
--- ns-3.41/src/wifi/model/frame-exchange-manager.h	2024-02-09 14:44:08.581795000 -0800
+++ ns-3.42/src/wifi/model/frame-exchange-manager.h	2024-05-29 15:29:47.200073700 -0700
@@ -37,6 +37,9 @@
 
 #include "ns3/object.h"
 
+#define WIFI_FEM_NS_LOG_APPEND_CONTEXT                                                             \
+    std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+
 namespace ns3
 {
 
@@ -547,7 +550,7 @@
      * \param rtsTxMode the TX mode used to transmit the RTS
      * \param rtsSnr the SNR of the RTS in linear scale
      */
-    void SendCtsAfterRts(const WifiMacHeader& rtsHdr, WifiMode rtsTxMode, double rtsSnr);
+    virtual void SendCtsAfterRts(const WifiMacHeader& rtsHdr, WifiMode rtsTxMode, double rtsSnr);
 
     /**
      * Send CTS after receiving RTS.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-6ghz-band-capabilities.cc ns-3.42/src/wifi/model/he/he-6ghz-band-capabilities.cc
--- ns-3.41/src/wifi/model/he/he-6ghz-band-capabilities.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/he/he-6ghz-band-capabilities.cc	2024-05-29 15:29:47.200073700 -0700
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2024
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Rami Abdallah <abdallah.rami@gmail.com>
+ */
+
+#include "he-6ghz-band-capabilities.h"
+
+namespace ns3
+{
+
+He6GhzBandCapabilities::He6GhzBandCapabilities()
+    : m_capabilitiesInfo{}
+{
+}
+
+WifiInformationElementId
+He6GhzBandCapabilities::ElementId() const
+{
+    return IE_EXTENSION;
+}
+
+WifiInformationElementId
+He6GhzBandCapabilities::ElementIdExt() const
+{
+    return IE_EXT_HE_6GHZ_CAPABILITIES;
+}
+
+uint16_t
+He6GhzBandCapabilities::GetInformationFieldSize() const
+{
+    // Return size of Element ID Extension and
+    // Capabilities Information field in octets
+    return 1 + /* Element ID Ext */ +2 /* Capabilities Information */;
+}
+
+void
+He6GhzBandCapabilities::SetMaxAmpduLength(uint32_t maxAmpduLength)
+{
+    for (uint8_t i = 0; i <= 7; i++)
+    {
+        if ((1UL << (13 + i)) - 1 == maxAmpduLength)
+        {
+            m_capabilitiesInfo.m_maxAmpduLengthExponent = i;
+            return;
+        }
+    }
+    NS_ABORT_MSG("Invalid A-MPDU Max Length value");
+}
+
+uint32_t
+He6GhzBandCapabilities::GetMaxAmpduLength() const
+{
+    return (1UL << (13 + m_capabilitiesInfo.m_maxAmpduLengthExponent)) - 1;
+}
+
+void
+He6GhzBandCapabilities::SetMaxMpduLength(uint16_t length)
+{
+    NS_ABORT_MSG_IF(length != 3895 && length != 7991 && length != 11454,
+                    "Invalid MPDU Max Length value");
+    if (length == 11454)
+    {
+        m_capabilitiesInfo.m_maxMpduLength = 2;
+    }
+    else if (length == 7991)
+    {
+        m_capabilitiesInfo.m_maxMpduLength = 1;
+    }
+    else
+    {
+        m_capabilitiesInfo.m_maxMpduLength = 0;
+    }
+}
+
+uint16_t
+He6GhzBandCapabilities::GetMaxMpduLength() const
+{
+    if (m_capabilitiesInfo.m_maxMpduLength == 0)
+    {
+        return 3895;
+    }
+    if (m_capabilitiesInfo.m_maxMpduLength == 1)
+    {
+        return 7991;
+    }
+    if (m_capabilitiesInfo.m_maxMpduLength == 2)
+    {
+        return 11454;
+    }
+    NS_ABORT_MSG("The value 3 is reserved");
+}
+
+void
+He6GhzBandCapabilities::SerializeInformationField(Buffer::Iterator start) const
+{
+    uint16_t twoBytes = m_capabilitiesInfo.m_minMpduStartSpacing |
+                        (m_capabilitiesInfo.m_maxAmpduLengthExponent << 3) |
+                        (m_capabilitiesInfo.m_maxMpduLength << 6) |
+                        (m_capabilitiesInfo.m_smPowerSave << 9) |
+                        (m_capabilitiesInfo.m_rdResponder << 11) |
+                        (m_capabilitiesInfo.m_rxAntennaPatternConsistency << 12) |
+                        (m_capabilitiesInfo.m_txAntennaPatternConsistency << 13);
+    start.WriteHtolsbU16(twoBytes);
+}
+
+uint16_t
+He6GhzBandCapabilities::DeserializeInformationField(Buffer::Iterator start, uint16_t length)
+{
+    Buffer::Iterator tmp = start;
+    uint16_t twoBytes = start.ReadLsbtohU16();
+    m_capabilitiesInfo.m_minMpduStartSpacing = twoBytes & 0x07;
+    m_capabilitiesInfo.m_maxAmpduLengthExponent = (twoBytes >> 3) & 0x07;
+    m_capabilitiesInfo.m_maxMpduLength = (twoBytes >> 6) & 0x03;
+    m_capabilitiesInfo.m_smPowerSave = (twoBytes >> 9) & 0x03;
+    m_capabilitiesInfo.m_rdResponder = (twoBytes >> 11) & 0x01;
+    m_capabilitiesInfo.m_rxAntennaPatternConsistency = (twoBytes >> 12) & 0x01;
+    m_capabilitiesInfo.m_txAntennaPatternConsistency = (twoBytes >> 13) & 0x01;
+    return start.GetDistanceFrom(tmp);
+}
+
+void
+He6GhzBandCapabilities::Print(std::ostream& os) const
+{
+    os << "HE 6GHz Band Capabilities=[Capabilities Information|"
+       << " Min MPDU start spacing: " << +m_capabilitiesInfo.m_minMpduStartSpacing
+       << " Max A-MPDU Length Exp: " << +m_capabilitiesInfo.m_maxAmpduLengthExponent
+       << " Max MPDU Length: " << +m_capabilitiesInfo.m_maxMpduLength
+       << " SM Power Save: " << +m_capabilitiesInfo.m_smPowerSave
+       << " RD Responder: " << +m_capabilitiesInfo.m_rdResponder
+       << " RX Antenna Pattern: " << +m_capabilitiesInfo.m_rxAntennaPatternConsistency
+       << " TX Antenna Pattern: " << +m_capabilitiesInfo.m_txAntennaPatternConsistency << "]";
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-6ghz-band-capabilities.h ns-3.42/src/wifi/model/he/he-6ghz-band-capabilities.h
--- ns-3.41/src/wifi/model/he/he-6ghz-band-capabilities.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/he/he-6ghz-band-capabilities.h	2024-05-29 15:29:47.200073700 -0700
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2024
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Rami Abdallah <abdallah.rami@gmail.com>
+ */
+
+#ifndef HE_6GHZ_BAND_CAPABILITIES_H
+#define HE_6GHZ_BAND_CAPABILITIES_H
+
+#include "ns3/wifi-information-element.h"
+
+namespace ns3
+{
+
+/**
+ * \ingroup wifi
+ *
+ * The HE 6 GHz Band Capabilities (IEEE 802.11ax-2021 9.4.2.263)
+ */
+class He6GhzBandCapabilities : public WifiInformationElement
+{
+  public:
+    He6GhzBandCapabilities();
+
+    WifiInformationElementId ElementId() const override;
+    WifiInformationElementId ElementIdExt() const override;
+    void Print(std::ostream& os) const override;
+
+    /// Capabilities Information field
+    struct CapabilitiesInfo
+    {
+        uint8_t m_minMpduStartSpacing : 3;         ///< Minimum MPDU Start Spacing
+        uint8_t m_maxAmpduLengthExponent : 3;      ///< Maximum A-MPDU Length Exponent (can
+                                                   ///< also be set via convenient methods)
+        uint8_t m_maxMpduLength : 2;               ///< Maximum MPDU Length (can also
+                                                   ///< be set via convenient methods)
+        uint8_t : 1;                               ///< Reserved Bits
+        uint8_t m_smPowerSave : 2;                 ///< SM Power Save
+        uint8_t m_rdResponder : 1;                 ///< RD Responder
+        uint8_t m_rxAntennaPatternConsistency : 1; ///< Receive Antenna Pattern Consistency
+        uint8_t m_txAntennaPatternConsistency : 1; ///< Transmit Antenna Pattern Consistency
+        uint8_t : 2;                               ///< Reserved Bits
+    };
+
+    CapabilitiesInfo m_capabilitiesInfo; ///< capabilities field
+
+    /**
+     * Set the maximum AMPDU length.
+     *
+     * \param maxAmpduLength 2^(13 + x) - 1, x in the range 0 to 7
+     */
+    void SetMaxAmpduLength(uint32_t maxAmpduLength);
+    /**
+     * Return the maximum A-MPDU length.
+     *
+     * \return the maximum A-MPDU length in bytes
+     */
+    uint32_t GetMaxAmpduLength() const;
+
+    /**
+     * Set the maximum MPDU length.
+     *
+     * \param length the maximum MPDU length (3895, 7991 or 11454)
+     */
+    void SetMaxMpduLength(uint16_t length);
+    /**
+     * Get the maximum MPDU length.
+     *
+     * \return the maximum MPDU length in bytes
+     */
+    uint16_t GetMaxMpduLength() const;
+
+  private:
+    uint16_t GetInformationFieldSize() const override;
+    void SerializeInformationField(Buffer::Iterator start) const override;
+    uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
+};
+
+} // namespace ns3
+
+#endif /* HE_6GHZ_BAND_CAPABILITY_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-frame-exchange-manager.cc ns-3.42/src/wifi/model/he/he-frame-exchange-manager.cc
--- ns-3.41/src/wifi/model/he/he-frame-exchange-manager.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-frame-exchange-manager.cc	2024-05-29 15:29:47.200073700 -0700
@@ -37,7 +37,7 @@
 #include <functional>
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
@@ -88,7 +88,7 @@
 HeFrameExchangeManager::Reset()
 {
     NS_LOG_FUNCTION(this);
-    if (m_intraBssNavResetEvent.IsRunning())
+    if (m_intraBssNavResetEvent.IsPending())
     {
         m_intraBssNavResetEvent.Cancel();
     }
@@ -212,7 +212,7 @@
     // can reuse this value.
     NS_ASSERT(m_txParams.m_acknowledgment);
 
-    if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
+    if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
     {
         CalculateAcknowledgmentTime(m_txParams.m_acknowledgment.get());
     }
@@ -233,7 +233,7 @@
                                          << ") incompatible with BSRP Trigger Frame");
         // Add a SIFS and the TB PPDU duration to the acknowledgment time of the Trigger Frame
         auto txVector = trigger.GetHeTbTxVector(trigger.begin()->GetAid12());
-        m_txParams.m_acknowledgment->acknowledgmentTime +=
+        *m_txParams.m_acknowledgment->acknowledgmentTime +=
             m_phy->GetSifs() + HePhy::ConvertLSigLengthToHeTbPpduDuration(trigger.GetUlLength(),
                                                                           txVector,
                                                                           m_phy->GetPhyBand());
@@ -360,12 +360,13 @@
 
     auto mpdu = Create<WifiMpdu>(payload, hdr);
 
-    NS_ASSERT(txParams.m_txDuration != Time::Min());
+    NS_ASSERT(txParams.m_txDuration.has_value());
+    NS_ASSERT(txParams.m_acknowledgment->acknowledgmentTime.has_value());
     mpdu->GetHeader().SetDuration(
         GetMuRtsDurationId(mpdu->GetSize(),
                            protection->muRtsTxVector,
-                           txParams.m_txDuration,
-                           txParams.m_acknowledgment->acknowledgmentTime));
+                           *txParams.m_txDuration,
+                           *txParams.m_acknowledgment->acknowledgmentTime));
 
     // Get the TXVECTOR used by one station to send the CTS response. This is used
     // to compute the preamble duration, so it does not matter which station we choose
@@ -536,8 +537,7 @@
         // schedule the transmission of required BlockAckReq frames
         for (const auto& psdu : m_psduMap)
         {
-            if (acknowledgment->stationsSendBlockAckReqTo.find(psdu.second->GetAddr1()) !=
-                acknowledgment->stationsSendBlockAckReqTo.end())
+            if (acknowledgment->stationsSendBlockAckReqTo.contains(psdu.second->GetAddr1()))
             {
                 // the receiver of this PSDU will receive a BlockAckReq
                 std::set<uint8_t> tids = psdu.second->GetTids();
@@ -625,7 +625,7 @@
                                                          acknowledgment->muBarTxVector,
                                                          m_phy->GetPhyBand());
             // update acknowledgmentTime to correctly set the Duration/ID
-            acknowledgment->acknowledgmentTime -= (m_phy->GetSifs() + txDuration);
+            *acknowledgment->acknowledgmentTime -= (m_phy->GetSifs() + txDuration);
             m_triggerFrame->GetHeader().SetDuration(GetPsduDurationId(txDuration, m_txParams));
 
             responseTxVector =
@@ -1233,13 +1233,14 @@
         txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
     {
         // we need to account for the size of the aggregated MU-BAR Trigger Frame
-        auto acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
-
-        const auto& info = acknowledgment->stationsReplyingWithBlockAck.find(receiver);
-        NS_ASSERT(info != acknowledgment->stationsReplyingWithBlockAck.end());
-
-        ppduPayloadSize =
-            MpduAggregator::GetSizeIfAggregated(info->second.muBarSize, ppduPayloadSize);
+        auto psduInfo = txParams.GetPsduInfo(receiver);
+        NS_ASSERT_MSG(psduInfo, "No information for " << receiver << " in TX params");
+        NS_ASSERT_MSG(!psduInfo->seqNumbers.empty(), "No sequence number for " << receiver);
+        const auto tid = psduInfo->seqNumbers.cbegin()->first;
+
+        ppduPayloadSize = MpduAggregator::GetSizeIfAggregated(
+            GetMuBarSize({m_mac->GetBarTypeAsOriginator(receiver, tid)}),
+            ppduPayloadSize);
     }
 
     uint16_t staId = (txParams.m_txVector.IsDlMu() ? m_apMac->GetAssociationId(receiver, m_linkId)
@@ -1249,7 +1250,7 @@
                                                    m_phy->GetPhyBand(),
                                                    staId);
 
-    return std::max(psduDuration, txParams.m_txDuration);
+    return txParams.m_txDuration ? std::max(psduDuration, *txParams.m_txDuration) : psduDuration;
 }
 
 void
@@ -1272,7 +1273,7 @@
 
         TransmissionFailed();
     }
-    else if (!m_multiStaBaEvent.IsRunning())
+    else if (!m_multiStaBaEvent.IsPending())
     {
         m_edca->ResetCw(m_linkId);
         TransmissionSucceeded();
@@ -1829,8 +1830,7 @@
         return;
     }
 
-    WifiMacHeader header;
-    header.SetType(WIFI_MAC_QOSDATA_NULL);
+    WifiMacHeader header(WIFI_MAC_QOSDATA_NULL);
     header.SetAddr1(hdr.GetAddr2());
     header.SetAddr2(m_self);
     header.SetAddr3(hdr.GetAddr2());
@@ -1852,36 +1852,38 @@
                                                                    m_phy->GetPhyBand());
     header.SetDuration(hdr.GetDuration() - m_phy->GetSifs() - ppduDuration);
 
-    Ptr<WifiMpdu> mpdu;
     std::vector<Ptr<WifiMpdu>> mpduList;
-    uint8_t tid = 0;
-    header.SetQosTid(tid);
 
-    while (tid < 8 &&
-           IsWithinSizeAndTimeLimits(
-               txParams.GetSizeIfAddMpdu(mpdu = Create<WifiMpdu>(Create<Packet>(), header)),
-               hdr.GetAddr2(),
-               txParams,
-               ppduDuration))
+    for (uint8_t tid = 0; tid < 8; ++tid)
     {
         if (!m_mac->GetBaAgreementEstablishedAsOriginator(hdr.GetAddr2(), tid))
         {
             NS_LOG_DEBUG("Skipping tid=" << +tid << " because no agreement established");
-            header.SetQosTid(++tid);
             continue;
         }
 
-        NS_LOG_DEBUG("Aggregating a QoS Null frame with tid=" << +tid);
-        // We could call TryAddMpdu instead of IsWithinSizeAndTimeLimits above in order to
+        // We could call TryAddMpdu instead of IsWithinSizeAndTimeLimits below in order to
         // get the TX parameters updated automatically. However, aggregating the QoS Null
         // frames might fail because MPDU aggregation is disabled by default for VO
         // and BK. Therefore, we skip the check on max A-MPDU size and only update the
         // TX parameters below.
-        txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
+        header.SetQosTid(tid);
+        auto mpdu = Create<WifiMpdu>(Create<Packet>(), header);
         txParams.AddMpdu(mpdu);
-        UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
+        UpdateTxDuration(header.GetAddr1(), txParams);
+
+        if (!IsWithinSizeAndTimeLimits(txParams.GetSize(header.GetAddr1()),
+                                       hdr.GetAddr2(),
+                                       txParams,
+                                       ppduDuration))
+        {
+            txParams.UndoAddMpdu();
+            break;
+        }
+
+        NS_LOG_DEBUG("Aggregating a QoS Null frame with tid=" << +tid);
+        txParams.m_acknowledgment = GetAckManager()->TryAddMpdu(mpdu, txParams);
         mpduList.push_back(mpdu);
-        header.SetQosTid(++tid);
     }
 
     if (mpduList.empty())
@@ -2097,19 +2099,20 @@
     m_channelAccessManager->NotifyNavResetNow(basicNav);
 }
 
-void
-HeFrameExchangeManager::SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
+std::optional<Mac48Address>
+HeFrameExchangeManager::FindTxopHolder(const WifiMacHeader& hdr, const WifiTxVector& txVector)
 {
-    NS_LOG_FUNCTION(this << psdu << txVector);
+    NS_LOG_FUNCTION(this << hdr << txVector);
 
-    if (psdu->GetHeader(0).IsTrigger() && psdu->GetAddr2() == m_bssid)
+    if (hdr.IsTrigger() && hdr.GetAddr2() == m_bssid)
     {
-        m_txopHolder = m_bssid;
+        return m_bssid;
     }
-    else if (!txVector.IsUlMu()) // the sender of a TB PPDU is not the TXOP holder
+    if (!txVector.IsUlMu()) // the sender of a TB PPDU is not the TXOP holder
     {
-        VhtFrameExchangeManager::SetTxopHolder(psdu, txVector);
+        return VhtFrameExchangeManager::FindTxopHolder(hdr, txVector);
     }
+    return std::nullopt;
 }
 
 bool
@@ -2184,7 +2187,7 @@
         auto acknowledgment = static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
         std::size_t index = acknowledgment->baType.m_bitmapLen.size();
 
-        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
+        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2235,7 +2238,7 @@
         }
 
         // Schedule the transmission of a Multi-STA BlockAck frame if needed
-        if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
+        if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
         {
             m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
                                                     &HeFrameExchangeManager::SendMultiStaBlockAck,
@@ -2253,7 +2256,7 @@
             m_txTimer.Cancel();
             m_channelAccessManager->NotifyAckTimeoutResetNow();
 
-            if (!m_multiStaBaEvent.IsRunning())
+            if (!m_multiStaBaEvent.IsPending())
             {
                 // all of the stations that replied with a TB PPDU sent QoS Null frames.
                 NS_LOG_DEBUG("Continue the TXOP");
@@ -2273,7 +2276,7 @@
     {
         const auto& sender = hdr.GetAddr2();
 
-        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
+        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2404,7 +2407,7 @@
                                                                m_txParams.m_txVector);
 
             // remove the sender from the set of stations that are expected to send a BlockAck
-            if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
+            if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
             {
                 NS_LOG_WARN("Received a BlockAck from an unexpected stations: " << sender);
                 return;
@@ -2657,7 +2660,7 @@
         auto acknowledgment = static_cast<WifiUlMuMultiStaBa*>(m_txParams.m_acknowledgment.get());
         std::size_t index = acknowledgment->baType.m_bitmapLen.size();
 
-        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
+        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
@@ -2693,7 +2696,7 @@
         }
 
         // Schedule the transmission of a Multi-STA BlockAck frame if needed
-        if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsRunning())
+        if (!acknowledgment->stationsReceivingMultiStaBa.empty() && !m_multiStaBaEvent.IsPending())
         {
             m_multiStaBaEvent = Simulator::Schedule(m_phy->GetSifs(),
                                                     &HeFrameExchangeManager::SendMultiStaBlockAck,
@@ -2711,7 +2714,7 @@
             m_txTimer.Cancel();
             m_channelAccessManager->NotifyAckTimeoutResetNow();
 
-            if (!m_multiStaBaEvent.IsRunning())
+            if (!m_multiStaBaEvent.IsPending())
             {
                 // all of the stations that replied with a TB PPDU sent QoS Null frames.
                 NS_LOG_DEBUG("Continue the TXOP");
@@ -2730,7 +2733,7 @@
     {
         Mac48Address sender = psdu->GetAddr2();
 
-        if (m_txTimer.GetStasExpectedToRespond().count(sender) == 0)
+        if (!m_txTimer.GetStasExpectedToRespond().contains(sender))
         {
             NS_LOG_WARN("Received a TB PPDU from an unexpected station: " << sender);
             return;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-frame-exchange-manager.h ns-3.42/src/wifi/model/he/he-frame-exchange-manager.h
--- ns-3.41/src/wifi/model/he/he-frame-exchange-manager.h	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-frame-exchange-manager.h	2024-05-29 15:29:47.200073700 -0700
@@ -79,7 +79,8 @@
     void SetWifiMac(const Ptr<WifiMac> mac) override;
     void CalculateAcknowledgmentTime(WifiAcknowledgment* acknowledgment) const override;
     void CalculateProtectionTime(WifiProtection* protection) const override;
-    void SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) override;
+    std::optional<Mac48Address> FindTxopHolder(const WifiMacHeader& hdr,
+                                               const WifiTxVector& txVector) override;
     bool VirtualCsMediumIdle() const override;
 
     /**
@@ -219,9 +220,9 @@
      * \param trigger the MU-RTS Trigger Frame header
      * \param muRtsSnr the SNR of the MU-RTS in linear scale
      */
-    void SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr,
-                           const CtrlTriggerHeader& trigger,
-                           double muRtsSnr);
+    virtual void SendCtsAfterMuRts(const WifiMacHeader& muRtsHdr,
+                                   const CtrlTriggerHeader& trigger,
+                                   double muRtsSnr);
 
     /**
      * \return the mode used to transmit a CTS after an MU-RTS.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-operation.cc ns-3.42/src/wifi/model/he/he-operation.cc
--- ns-3.41/src/wifi/model/he/he-operation.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-operation.cc	2024-05-29 15:29:47.200073700 -0700
@@ -14,7 +14,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
+ * Authors: Sébastien Deronne <sebastien.deronne@gmail.com>
+ *          Stefano Avallone <stavallo@unina.it>
  */
 
 #include "he-operation.h"
@@ -23,16 +24,8 @@
 {
 
 HeOperation::HeOperation()
-    : m_bssColor(0),
-      m_defaultPEDuration(0),
-      m_twtRequired(0),
-      m_heDurationBasedRtsThreshold(0),
-      m_partialBssColor(0),
-      m_maxBssidIndicator(0),
-      m_txBssidIndicator(0),
-      m_bssColorDisabled(0),
-      m_dualBeacon(0),
-      m_basicHeMcsAndNssSet(0xfffc)
+    : m_basicHeMcsAndNssSet(0xffff),
+      m_6GHzOpInfo(m_heOpParams.m_6GHzOpPresent)
 {
 }
 
@@ -49,45 +42,118 @@
 }
 
 void
-HeOperation::Print(std::ostream& os) const
+HeOperation::HeOperationParams::Print(std::ostream& os) const
 {
-    os << "HE Operation=" << GetHeOperationParameters() << "|" << GetBasicHeMcsAndNssSet();
+    os << "Default PE Duration: " << +m_defaultPeDuration << " TWT Required: " << +m_twtRequired
+       << " TXOP Duration RTS Threshold: " << m_txopDurRtsThresh
+       << " VHT Operation Information Present: " << +m_vhOpPresent
+       << " Co-Hosted BSS: " << +m_coHostedBss << " ER SU Disable: " << +m_erSuDisable
+       << " 6 GHz Operation Information Present: " << m_6GHzOpPresent;
 }
 
 uint16_t
-HeOperation::GetInformationFieldSize() const
+HeOperation::HeOperationParams::GetSerializedSize() const
+{
+    return 3;
+}
+
+void
+HeOperation::HeOperationParams::Serialize(Buffer::Iterator& start) const
+{
+    uint16_t twoBytes = m_defaultPeDuration | (m_twtRequired << 3) | (m_txopDurRtsThresh << 4) |
+                        (m_vhOpPresent << 14) | (m_coHostedBss << 15);
+    uint8_t oneByte = m_erSuDisable | ((m_6GHzOpPresent ? 1 : 0) << 1);
+    start.WriteHtolsbU16(twoBytes);
+    start.WriteU8(oneByte);
+}
+
+uint16_t
+HeOperation::HeOperationParams::Deserialize(Buffer::Iterator& start)
+{
+    Buffer::Iterator tmp = start;
+    uint16_t twoBytes = start.ReadLsbtohU16();
+    uint8_t oneByte = start.ReadU8();
+    m_defaultPeDuration = twoBytes & 0x07;
+    m_twtRequired = (twoBytes >> 3) & 0x01;
+    m_txopDurRtsThresh = (twoBytes >> 4) & 0x03ff;
+    m_vhOpPresent = (twoBytes >> 14) & 0x01;
+    m_coHostedBss = (twoBytes >> 15) & 0x01;
+    m_erSuDisable = oneByte & 0x01;
+    m_6GHzOpPresent = ((oneByte >> 1) & 0x01) == 1;
+    return start.GetDistanceFrom(tmp);
+}
+
+void
+HeOperation::BssColorInfo::Print(std::ostream& os) const
+{
+    os << "BSS Color: " << +m_bssColor << " Partial BSS Color: " << +m_partialBssColor
+       << " BSS Color Disabled: " << +m_bssColorDisabled;
+}
+
+uint16_t
+HeOperation::BssColorInfo::GetSerializedSize() const
+{
+    return 1;
+}
+
+void
+HeOperation::BssColorInfo::Serialize(Buffer::Iterator& start) const
+{
+    uint8_t oneByte = m_bssColor | (m_partialBssColor << 6) | (m_bssColorDisabled << 7);
+    start.WriteU8(oneByte);
+}
+
+uint16_t
+HeOperation::BssColorInfo::Deserialize(Buffer::Iterator& start)
+{
+    Buffer::Iterator tmp = start;
+    uint8_t oneByte = start.ReadU8();
+    m_bssColor = oneByte & 0x3f;
+    m_partialBssColor = (oneByte >> 6) & 0x01;
+    m_bssColorDisabled = (oneByte >> 7) & 0x01;
+    return start.GetDistanceFrom(tmp);
+}
+
+void
+HeOperation::OpInfo6GHz::Print(std::ostream& os) const
 {
-    return 7;
+    os << "Primary channel: " << +m_primCh << " Channel Width: " << +m_chWid
+       << " Duplicate Beacon: " << +m_dupBeacon << " Regulatory Info: " << +m_regInfo
+       << " Channel center frequency segment 0: " << +m_chCntrFreqSeg0
+       << " Channel center frequency segment 1: " << +m_chCntrFreqSeg1
+       << " Minimum Rate: " << +m_minRate;
+}
+
+uint16_t
+HeOperation::OpInfo6GHz::GetSerializedSize() const
+{
+    return 5;
 }
 
 void
-HeOperation::SetHeOperationParameters(uint32_t ctrl)
+HeOperation::OpInfo6GHz::Serialize(Buffer::Iterator& start) const
+{
+    start.WriteU8(m_primCh);
+    uint8_t control = m_chWid | (m_dupBeacon << 2) | (m_regInfo << 3);
+    start.WriteU8(control);
+    start.WriteU8(m_chCntrFreqSeg0);
+    start.WriteU8(m_chCntrFreqSeg1);
+    start.WriteU8(m_minRate);
+}
+
+uint16_t
+HeOperation::OpInfo6GHz::Deserialize(Buffer::Iterator& start)
 {
-    m_bssColor = ctrl & 0x3f;
-    m_defaultPEDuration = (ctrl >> 6) & 0x07;
-    m_twtRequired = (ctrl >> 9) & 0x01;
-    m_heDurationBasedRtsThreshold = (ctrl >> 10) & 0x03ff;
-    m_partialBssColor = (ctrl >> 20) & 0x01;
-    m_maxBssidIndicator = (ctrl >> 21) & 0xff;
-    m_txBssidIndicator = (ctrl >> 29) & 0x01;
-    m_bssColorDisabled = (ctrl >> 30) & 0x01;
-    m_dualBeacon = (ctrl >> 31) & 0x01;
-}
-
-uint32_t
-HeOperation::GetHeOperationParameters() const
-{
-    uint32_t val = 0;
-    val |= m_bssColor & 0x3f;
-    val |= (m_defaultPEDuration & 0x07) << 6;
-    val |= (m_twtRequired & 0x01) << 9;
-    val |= (m_heDurationBasedRtsThreshold & 0x03ff) << 10;
-    val |= (m_partialBssColor & 0x01) << 20;
-    val |= (m_maxBssidIndicator & 0xff) << 21;
-    val |= (m_txBssidIndicator & 0x01) << 29;
-    val |= (m_bssColorDisabled & 0x01) << 30;
-    val |= (m_dualBeacon & 0x01) << 31;
-    return val;
+    Buffer::Iterator i = start;
+    m_primCh = i.ReadU8();
+    uint8_t control = i.ReadU8();
+    m_chWid = control & 0x03;
+    m_dupBeacon = (control >> 2) & 0x01;
+    m_regInfo = (control >> 3) & 0x07;
+    m_chCntrFreqSeg0 = i.ReadU8();
+    m_chCntrFreqSeg1 = i.ReadU8();
+    m_minRate = i.ReadU8();
+    return i.GetDistanceFrom(start);
 }
 
 void
@@ -97,17 +163,17 @@
 
     // IEEE 802.11ax-2021 9.4.2.248.4 Supported HE-MCS And NSS Set field
     uint8_t val = 0x03; // not supported
-    if (maxHeMcs > 9)   // MCS 0 - 11
+    if (maxHeMcs == 11) // MCS 0 - 11
     {
         val = 0x02;
     }
-    else if (maxHeMcs > 7) // MCS 0 - 9
+    else if (maxHeMcs >= 9) // MCS 0 - 9
     {
         val = 0x01;
     }
-    else if (maxHeMcs == 7) // MCS 0 - 7
+    else // MCS 0 - 7
     {
-        val = 0x01;
+        val = 0x00;
     }
 
     // clear bits for that nss
@@ -118,32 +184,44 @@
     m_basicHeMcsAndNssSet |= ((val & 0x03) << ((nss - 1) * 2));
 }
 
-uint16_t
-HeOperation::GetBasicHeMcsAndNssSet() const
-{
-    return m_basicHeMcsAndNssSet;
-}
-
 void
-HeOperation::SetBssColor(uint8_t bssColor)
+HeOperation::Print(std::ostream& os) const
 {
-    NS_ABORT_UNLESS(bssColor < 64); // 6 bits
-    m_bssColor = bssColor;
-    m_bssColorDisabled = 0;
+    os << "HE Operation=[HE Operation Parameters|";
+    m_heOpParams.Print(os);
+    os << "][BSS Color|";
+    m_bssColorInfo.Print(os);
+    os << "][Basic HE-MCS And NSS Set: " << m_basicHeMcsAndNssSet << "]";
+    if (m_6GHzOpInfo)
+    {
+        os << "[6 GHz Operation Info|";
+        m_6GHzOpInfo->Print(os);
+        os << "]";
+    }
 }
 
-uint8_t
-HeOperation::GetBssColor() const
+uint16_t
+HeOperation::GetInformationFieldSize() const
 {
-    return m_bssColor;
+    uint16_t ret = 1 /* Element ID Ext */ + m_heOpParams.GetSerializedSize() +
+                   m_bssColorInfo.GetSerializedSize() + 2 /* Basic HE-MCS And NSS Set */;
+    if (m_6GHzOpInfo)
+    {
+        ret += m_6GHzOpInfo->GetSerializedSize();
+    }
+    return ret;
 }
 
 void
 HeOperation::SerializeInformationField(Buffer::Iterator start) const
 {
-    // write the corresponding value for each bit
-    start.WriteHtolsbU32(GetHeOperationParameters());
-    start.WriteU16(GetBasicHeMcsAndNssSet());
+    m_heOpParams.Serialize(start);
+    m_bssColorInfo.Serialize(start);
+    start.WriteHtolsbU16(m_basicHeMcsAndNssSet);
+    if (m_6GHzOpInfo)
+    {
+        m_6GHzOpInfo->Serialize(start);
+    }
     // todo: VHT Operation Information (variable)
 }
 
@@ -151,11 +229,18 @@
 HeOperation::DeserializeInformationField(Buffer::Iterator start, uint16_t length)
 {
     Buffer::Iterator i = start;
-    uint32_t heOperationParameters = i.ReadLsbtohU32();
-    m_basicHeMcsAndNssSet = i.ReadU16();
-    SetHeOperationParameters(heOperationParameters);
+    m_heOpParams.Deserialize(i);
+    m_bssColorInfo.Deserialize(i);
+    m_basicHeMcsAndNssSet = i.ReadLsbtohU16();
+    if (m_heOpParams.m_6GHzOpPresent)
+    {
+        OpInfo6GHz opInfo6GHz;
+        opInfo6GHz.Deserialize(i);
+        m_6GHzOpInfo = opInfo6GHz;
+    }
+
     // todo: VHT Operation Information (variable)
-    return length;
+    return i.GetDistanceFrom(start);
 }
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-operation.h ns-3.42/src/wifi/model/he/he-operation.h
--- ns-3.41/src/wifi/model/he/he-operation.h	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-operation.h	2024-05-29 15:29:47.200073700 -0700
@@ -14,13 +14,15 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
+ * Authors: Sébastien Deronne <sebastien.deronne@gmail.com>
+ *          Stefano Avallone <stavallo@unina.it>
  */
 
 #ifndef HE_OPERATION_H
 #define HE_OPERATION_H
 
 #include "ns3/wifi-information-element.h"
+#include "ns3/wifi-opt-field.h"
 
 namespace ns3
 {
@@ -42,64 +44,140 @@
     WifiInformationElementId ElementIdExt() const override;
     void Print(std::ostream& os) const override;
 
-    /**
-     * Set the HE Operation Parameters field in the HE Operation information element.
-     *
-     * \param ctrl the HE Operation Parameters field in the HE Operation information element
-     */
-    void SetHeOperationParameters(uint32_t ctrl);
+    /// HE Operation Parameters field
+    struct HeOperationParams
+    {
+        uint8_t m_defaultPeDuration : 3 {0};  ///< Default PE Duration
+        uint8_t m_twtRequired : 1 {0};        ///< TWT Required
+        uint16_t m_txopDurRtsThresh : 10 {0}; ///< TXOP Duration RTS Threshold
+        uint8_t m_vhOpPresent : 1 {0}; ///< VHT Operation Information Present (value 1 unsupported)
+        uint8_t m_coHostedBss : 1 {0}; ///< Co-Hosted BSS (value 1 unsupported)
+        uint8_t m_erSuDisable : 1 {0}; ///< ER SU Disable
+        bool m_6GHzOpPresent{false};   ///< 6 GHz Operation Information Present (do not set, it is
+                                       ///< set by the OptFieldWithPresenceInd)
+
+        /**
+         * Print the content of the HE Operation Parameters field.
+         *
+         * \param os output stream
+         */
+        void Print(std::ostream& os) const;
+
+        /**
+         * \return the serialized size of the HE Operation Parameters field
+         */
+        uint16_t GetSerializedSize() const;
+
+        /**
+         * Serialize the HE Operation Parameters field
+         *
+         * \param start an iterator which points to where the information should be written
+         */
+        void Serialize(Buffer::Iterator& start) const;
+
+        /**
+         * Deserialize the HE Operation Parameters field.
+         *
+         * \param start an iterator which points to where the information should be read from
+         * \return the number of bytes read
+         */
+        uint16_t Deserialize(Buffer::Iterator& start);
+    };
+
+    /// BSS Color Information field
+    struct BssColorInfo
+    {
+        uint8_t m_bssColor : 6 {0};         ///< BSS Color
+        uint8_t m_partialBssColor : 1 {0};  ///< Partial BSS Color
+        uint8_t m_bssColorDisabled : 1 {0}; ///< BSS Color Disabled
+
+        /**
+         * Print the content of the BSS Color Information field.
+         *
+         * \param os output stream
+         */
+        void Print(std::ostream& os) const;
+
+        /**
+         * \return the serialized size of the BSS Color Information field
+         */
+        uint16_t GetSerializedSize() const;
+
+        /**
+         * Serialize the BSS Color Information field
+         *
+         * \param start an iterator which points to where the information should be written
+         */
+        void Serialize(Buffer::Iterator& start) const;
+
+        /**
+         * Deserialize the BSS Color Information field.
+         *
+         * \param start an iterator which points to where the information should be read from
+         * \return the number of bytes read
+         */
+        uint16_t Deserialize(Buffer::Iterator& start);
+    };
+
+    /// 6 GHz Operation Information field
+    struct OpInfo6GHz
+    {
+        uint8_t m_primCh{0};         ///< Primary Channel
+        uint8_t m_chWid : 2 {0};     ///< Channel Width
+        uint8_t m_dupBeacon : 1 {0}; ///< Duplicate Beacon
+        uint8_t m_regInfo : 3 {0};   ///< Regulatory Info
+        uint8_t : 2;                 ///< Reserved bits
+        uint8_t m_chCntrFreqSeg0{0}; ///< Channel center frequency segment 0
+        uint8_t m_chCntrFreqSeg1{0}; ///< Channel center frequency segment 1
+        uint8_t m_minRate{0};        ///< Minimum Rate
+
+        /**
+         * Print the content of the 6 GHz Operation Information field.
+         *
+         * \param os output stream
+         */
+        void Print(std::ostream& os) const;
+
+        /**
+         * \return the serialized size of the 6 GHz Operation Information field
+         */
+        uint16_t GetSerializedSize() const;
+
+        /**
+         * Serialize the 6 GHz Operation Information field
+         *
+         * \param start an iterator which points to where the information should be written
+         */
+        void Serialize(Buffer::Iterator& start) const;
+
+        /**
+         * Deserialize the 6 GHz Operation Information field.
+         *
+         * \param start an iterator which points to where the information should be read from
+         * \return the number of bytes read
+         */
+        uint16_t Deserialize(Buffer::Iterator& start);
+    };
+
     /**
      * Set the Basic HE-MCS and NSS field in the HE Operation information element
-     * by specifying the tuple (<i>nss</i>, <i>maxMcs</i>).
+     * by specifying the pair (<i>nss</i>, <i>maxMcs</i>).
      *
      * \param nss the NSS
      * \param maxHeMcs the maximum supported HE-MCS value corresponding to that NSS
      */
     void SetMaxHeMcsPerNss(uint8_t nss, uint8_t maxHeMcs);
 
-    /**
-     * Return the HE Operation Parameters field in the HE Operation information element.
-     *
-     * \return the HE Operation Parameters field in the HE Operation information element
-     */
-    uint32_t GetHeOperationParameters() const;
-    /**
-     * Return the Basic HE-MCS And Nss field in the HE Operation information element.
-     *
-     * \return the Basic HE-MCS And Nss field in the HE Operation information element
-     */
-    uint16_t GetBasicHeMcsAndNssSet() const;
-    /**
-     * Set the BSS color
-     * \param bssColor the BSS color value
-     */
-    void SetBssColor(uint8_t bssColor);
-    /**
-     * Get the BSS color
-     * \return the BSS color value
-     */
-    uint8_t GetBssColor() const;
+    // Fields
+    HeOperationParams m_heOpParams; //!< HE Operation Parameters field
+    BssColorInfo m_bssColorInfo;    //!< BSS Color Information field
+    uint16_t m_basicHeMcsAndNssSet; ///< Basic HE-MCS And NSS set (use setter to set value)
+    OptFieldWithPresenceInd<OpInfo6GHz> m_6GHzOpInfo; ///< 6 GHz Operation Information field
 
   private:
     uint16_t GetInformationFieldSize() const override;
     void SerializeInformationField(Buffer::Iterator start) const override;
     uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
-
-    // HE Operation Parameters fields
-    uint8_t m_bssColor;                     //!< BSS color
-    uint8_t m_defaultPEDuration;            //!< default PE duration
-    uint8_t m_twtRequired;                  //!< TWT required
-    uint16_t m_heDurationBasedRtsThreshold; //!< HE duration based RTS threshold
-    uint8_t m_partialBssColor;              //!< partial BSS color
-    uint8_t m_maxBssidIndicator;            //!< max BSSID indicator
-    uint8_t m_txBssidIndicator;             //!< TX BSSID indicator
-    uint8_t m_bssColorDisabled;             //!< BSS color disabled
-    uint8_t m_dualBeacon;                   //!< Dual Beacon
-
-    // Basic HE-MCS and NSS Set
-    uint16_t m_basicHeMcsAndNssSet; ///< basic HE MCS NSS set
-
-    // TODO: VHT Operation Information subfields not defined in the standard yet.
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-phy.cc ns-3.42/src/wifi/model/he/he-phy.cc
--- ns-3.41/src/wifi/model/he/he-phy.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-phy.cc	2024-05-29 15:29:47.200073700 -0700
@@ -38,6 +38,9 @@
 
 #include <algorithm>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
@@ -382,7 +385,7 @@
                         << GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector).As(Time::NS));
             auto event = CreateInterferenceEvent(ppdu, rxDuration, rxPowersW, !hePortionStarted);
             uint16_t staId = GetStaId(ppdu);
-            NS_ASSERT(m_beginMuPayloadRxEvents.find(staId) == m_beginMuPayloadRxEvents.end());
+            NS_ASSERT(!m_beginMuPayloadRxEvents.contains(staId));
             m_beginMuPayloadRxEvents[staId] =
                 Simulator::Schedule(GetDuration(WIFI_PPDU_FIELD_TRAINING, txVector),
                                     &HePhy::StartReceiveMuPayload,
@@ -530,14 +533,14 @@
         (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
     {
         NS_LOG_DEBUG("Drop packet because already receiving another HE TB PPDU");
-        m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), RXING);
+        m_wifiPhy->NotifyRxPpduDrop(ppdu, RXING);
     }
     else if (const auto isResponseToTrigger = (m_previouslyTxPpduUid == ppdu->GetUid());
              isResponseToTrigger && GetCurrentEvent() &&
              (GetCurrentEvent()->GetPpdu()->GetUid() != ppdu->GetUid()))
     {
         NS_LOG_DEBUG("Drop packet because already receiving another response to a trigger frame");
-        m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), RXING);
+        m_wifiPhy->NotifyRxPpduDrop(ppdu, RXING);
     }
 }
 
@@ -668,8 +671,7 @@
                 return PhyFieldRxStatus(false, FILTERED, DROP);
             }
             uint16_t staId = ppdu->GetStaId();
-            if (m_trigVector->GetHeMuUserInfoMap().find(staId) ==
-                m_trigVector->GetHeMuUserInfoMap().end())
+            if (!m_trigVector->GetHeMuUserInfoMap().contains(staId))
             {
                 NS_LOG_DEBUG("TB PPDU received from un unexpected STA ID");
                 return PhyFieldRxStatus(false, FILTERED, DROP);
@@ -830,7 +832,7 @@
             Simulator::Schedule(timeToEndRx, &HePhy::ResetReceive, this, event));
         // Cancel all scheduled events for MU payload reception
         NS_ASSERT(!m_beginMuPayloadRxEvents.empty() &&
-                  m_beginMuPayloadRxEvents.begin()->second.IsRunning());
+                  m_beginMuPayloadRxEvents.begin()->second.IsPending());
         for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
         {
             beginMuPayloadRxEvent.second.Cancel();
@@ -848,7 +850,7 @@
         NS_ASSERT(!m_beginMuPayloadRxEvents.empty());
         for (auto& beginMuPayloadRxEvent : m_beginMuPayloadRxEvents)
         {
-            NS_ASSERT(beginMuPayloadRxEvent.second.IsRunning());
+            NS_ASSERT(beginMuPayloadRxEvent.second.IsPending());
         }
     }
 
@@ -1517,8 +1519,7 @@
         if (txVector.IsDlMu())
         {
             NS_ASSERT(txVector.GetModulationClass() >= WIFI_MOD_CLASS_HE);
-            WifiTxVector::HeMuUserInfoMap userInfoMap = txVector.GetHeMuUserInfoMap();
-            NS_ABORT_MSG_IF(userInfoMap.find(staIdPsdu.first) == userInfoMap.end(),
+            NS_ABORT_MSG_IF(!txVector.GetHeMuUserInfoMap().contains(staIdPsdu.first),
                             "STA-ID in psduMap (" << staIdPsdu.first
                                                   << ") should be referenced in txVector");
         }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-ppdu.cc ns-3.42/src/wifi/model/he/he-ppdu.cc
--- ns-3.41/src/wifi/model/he/he-ppdu.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-ppdu.cc	2024-05-29 15:29:47.200073700 -0700
@@ -466,7 +466,7 @@
     // HE TB PPDU reception needs information from the TRIGVECTOR to be able to receive the PPDU
     const auto staId = GetStaId();
     if (trigVector.has_value() && trigVector->IsUlMu() &&
-        (trigVector->GetHeMuUserInfoMap().count(staId) > 0))
+        (trigVector->GetHeMuUserInfoMap().contains(staId)))
     {
         // These information are not carried in HE-SIG-A for a HE TB PPDU,
         // but they are carried in the Trigger frame soliciting the HE TB PPDU
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/he-ru.cc ns-3.42/src/wifi/model/he/he-ru.cc
--- ns-3.41/src/wifi/model/he/he-ru.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/he-ru.cc	2024-05-29 15:29:47.200073700 -0700
@@ -393,25 +393,29 @@
 HeRu::GetRuSpecs(uint8_t ruAllocation)
 {
     std::optional<std::size_t> idx;
-    switch (ruAllocation)
+    if (((ruAllocation >= 0) && (ruAllocation <= 15)) || (ruAllocation == 112))
     {
-    case 0 ... 15:
-    case 112:
         idx = ruAllocation;
-        break;
-    case 16 ... 95:
-    case 192 ... 215:
+    }
+    else if (((ruAllocation >= 16) && (ruAllocation <= 95)) ||
+             ((ruAllocation >= 192) && (ruAllocation <= 215)))
+    {
         idx = ruAllocation & 0xF8;
-        break;
-    case 96 ... 111:
+    }
+    else if ((ruAllocation >= 96) && (ruAllocation <= 111))
+    {
         idx = ruAllocation & 0xF0;
-        break;
-    case 113 ... 115:
-        break;
-    case 128 ... 191:
+    }
+    else if ((ruAllocation >= 113) && (ruAllocation <= 115))
+    {
+        // Do not set idx to return an undefined RU allocation
+    }
+    else if ((ruAllocation >= 128) && (ruAllocation <= 191))
+    {
         idx = ruAllocation & 0xC0;
-        break;
-    default:
+    }
+    else
+    {
         NS_FATAL_ERROR("Reserved RU allocation " << +ruAllocation);
     }
     return idx.has_value() ? m_heRuAllocations.at(idx.value()) : std::vector<HeRu::RuSpec>{};
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/multi-user-scheduler.cc ns-3.42/src/wifi/model/he/multi-user-scheduler.cc
--- ns-3.41/src/wifi/model/he/multi-user-scheduler.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/multi-user-scheduler.cc	2024-05-29 15:29:47.200073700 -0700
@@ -210,7 +210,7 @@
     m_allowedWidth = allowedWidth;
     m_linkId = linkId;
 
-    if (m_accessReqTimer.IsRunning() && m_restartTimerUponAccess)
+    if (m_accessReqTimer.IsPending() && m_restartTimerUponAccess)
     {
         // restart access timer
         m_accessReqTimer.Cancel();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/mu-snr-tag.cc ns-3.42/src/wifi/model/he/mu-snr-tag.cc
--- ns-3.41/src/wifi/model/he/mu-snr-tag.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/mu-snr-tag.cc	2024-05-29 15:29:47.200073700 -0700
@@ -57,7 +57,7 @@
 bool
 MuSnrTag::IsPresent(uint16_t staId) const
 {
-    return (m_snrMap.find(staId) != m_snrMap.end());
+    return m_snrMap.contains(staId);
 }
 
 double
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/he/rr-multi-user-scheduler.cc ns-3.42/src/wifi/model/he/rr-multi-user-scheduler.cc
--- ns-3.41/src/wifi/model/he/rr-multi-user-scheduler.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/he/rr-multi-user-scheduler.cc	2024-05-29 15:29:47.200073700 -0700
@@ -302,7 +302,7 @@
     // only consider stations that have setup the current link
     WifiTxVector txVector = GetTxVectorForUlMu([this](const MasterInfo& info) {
         const auto& staList = m_apMac->GetStaList(m_linkId);
-        return staList.find(info.aid) != staList.cend();
+        return staList.contains(info.aid);
     });
 
     if (txVector.GetHeMuUserInfoMap().empty())
@@ -346,13 +346,13 @@
     if (m_availableTime != Time::Min())
     {
         // TryAddMpdu only considers the time to transmit the Trigger Frame
-        NS_ASSERT(m_txParams.m_protection &&
-                  m_txParams.m_protection->protectionTime != Time::Min());
+        NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
         NS_ASSERT(m_txParams.m_acknowledgment &&
-                  m_txParams.m_acknowledgment->acknowledgmentTime.IsZero());
-        NS_ASSERT(m_txParams.m_txDuration != Time::Min());
+                  m_txParams.m_acknowledgment->acknowledgmentTime.has_value() &&
+                  m_txParams.m_acknowledgment->acknowledgmentTime->IsZero());
+        NS_ASSERT(m_txParams.m_txDuration.has_value());
 
-        if (m_txParams.m_protection->protectionTime + m_txParams.m_txDuration // BSRP TF tx time
+        if (*m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // BSRP TF tx time
                 + m_apMac->GetWifiPhy(m_linkId)->GetSifs() + qosNullTxDuration >
             m_availableTime)
         {
@@ -390,8 +390,7 @@
     // reported a null queue size
     WifiTxVector txVector = GetTxVectorForUlMu([this](const MasterInfo& info) {
         const auto& staList = m_apMac->GetStaList(m_linkId);
-        return staList.find(info.aid) != staList.cend() &&
-               m_apMac->GetMaxBufferStatus(info.address) > 0;
+        return staList.contains(info.aid) && m_apMac->GetMaxBufferStatus(info.address) > 0;
     });
 
     if (txVector.GetHeMuUserInfoMap().empty())
@@ -458,16 +457,15 @@
     if (m_availableTime != Time::Min())
     {
         // TryAddMpdu only considers the time to transmit the Trigger Frame
-        NS_ASSERT(m_txParams.m_protection &&
-                  m_txParams.m_protection->protectionTime != Time::Min());
+        NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
         NS_ASSERT(m_txParams.m_acknowledgment &&
-                  m_txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
-        NS_ASSERT(m_txParams.m_txDuration != Time::Min());
+                  m_txParams.m_acknowledgment->acknowledgmentTime.has_value());
+        NS_ASSERT(m_txParams.m_txDuration.has_value());
 
         maxDuration = Min(maxDuration,
-                          m_availableTime - m_txParams.m_protection->protectionTime -
-                              m_txParams.m_txDuration - m_apMac->GetWifiPhy(m_linkId)->GetSifs() -
-                              m_txParams.m_acknowledgment->acknowledgmentTime);
+                          m_availableTime - *m_txParams.m_protection->protectionTime -
+                              *m_txParams.m_txDuration - m_apMac->GetWifiPhy(m_linkId)->GetSifs() -
+                              *m_txParams.m_acknowledgment->acknowledgmentTime);
         if (maxDuration.IsNegative())
         {
             NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
@@ -944,9 +942,10 @@
         }
     }
 
+    NS_ASSERT(dlMuInfo.txParams.m_txDuration.has_value());
     AcIndex primaryAc = m_edca->GetAccessCategory();
     UpdateCredits(m_staListDl[primaryAc],
-                  dlMuInfo.txParams.m_txDuration,
+                  *dlMuInfo.txParams.m_txDuration,
                   dlMuInfo.txParams.m_txVector);
 
     NS_LOG_DEBUG("Next station to serve has AID=" << m_staListDl[primaryAc].front().aid);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/ht/ht-frame-exchange-manager.cc ns-3.42/src/wifi/model/ht/ht-frame-exchange-manager.cc
--- ns-3.41/src/wifi/model/ht/ht-frame-exchange-manager.cc	2024-02-09 14:44:08.585795000 -0800
+++ ns-3.42/src/wifi/model/ht/ht-frame-exchange-manager.cc	2024-05-29 15:29:47.204074000 -0700
@@ -19,6 +19,8 @@
 
 #include "ht-frame-exchange-manager.h"
 
+#include "ht-configuration.h"
+
 #include "ns3/abort.h"
 #include "ns3/assert.h"
 #include "ns3/ctrl-headers.h"
@@ -29,13 +31,14 @@
 #include "ns3/sta-wifi-mac.h"
 #include "ns3/vht-configuration.h"
 #include "ns3/wifi-mac-queue.h"
+#include "ns3/wifi-net-device.h"
 #include "ns3/wifi-utils.h"
 
 #include <array>
 #include <optional>
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
@@ -110,21 +113,29 @@
     Ptr<QosTxop> qosTxop = m_mac->GetQosTxop(tid);
     bool establish;
 
-    if (!m_mac->GetHtSupported(recipient))
+    // NOLINTBEGIN(bugprone-branch-clone)
+    if (!m_mac->GetHtConfiguration() ||
+        (!GetWifiRemoteStationManager()->GetHtSupported(recipient) &&
+         !GetWifiRemoteStationManager()->GetStationHe6GhzCapabilities(recipient)))
     {
+        // no Block Ack if this device or the recipient are not HT STAs and do not operate
+        // in the 6 GHz band
         establish = false;
     }
     else if (auto agreement = qosTxop->GetBaManager()->GetAgreementAsOriginator(recipient, tid);
              agreement && !agreement->get().IsReset())
     {
+        // Block Ack agreement already established
         establish = false;
     }
+    // NOLINTEND(bugprone-branch-clone)
     else
     {
         WifiContainerQueueId queueId{WIFI_QOSDATA_QUEUE, WIFI_UNICAST, recipient, tid};
         uint32_t packets = qosTxop->GetWifiMacQueue()->GetNPackets(queueId);
         establish =
-            ((qosTxop->GetBlockAckThreshold() > 0 && packets >= qosTxop->GetBlockAckThreshold()) ||
+            (m_mac->Is6GhzBand(m_linkId) ||
+             (qosTxop->GetBlockAckThreshold() > 0 && packets >= qosTxop->GetBlockAckThreshold()) ||
              (m_mpduAggregator->GetMaxAmpduSize(recipient, tid, WIFI_MOD_CLASS_HT) > 0 &&
               packets > 1) ||
              m_mac->GetVhtConfiguration());
@@ -257,12 +268,9 @@
     {
         originator = *originatorMld;
     }
-    bool htSupported = GetWifiRemoteStationManager()->GetHtSupported() &&
-                       GetWifiRemoteStationManager()->GetHtSupported(originator);
     GetBaManager(tid)->CreateRecipientAgreement(respHdr,
                                                 originator,
                                                 reqHdr->GetStartingSequence(),
-                                                htSupported,
                                                 m_rxMiddle);
 
     auto agreement = GetBaManager(tid)->GetAgreementAsRecipient(originator, tid);
@@ -885,8 +893,8 @@
     if (m_edca->GetTxopLimit(m_linkId).IsZero())
     {
         NS_ASSERT(txParams.m_acknowledgment &&
-                  txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
-        return txParams.m_acknowledgment->acknowledgmentTime;
+                  txParams.m_acknowledgment->acknowledgmentTime.has_value());
+        return *txParams.m_acknowledgment->acknowledgmentTime;
     }
 
     // under multiple protection settings, if the TXOP limit is not null, Duration/ID
@@ -920,7 +928,7 @@
     // and SendCtsToSelf() can reuse this value.
     NS_ASSERT(m_txParams.m_acknowledgment);
 
-    if (m_txParams.m_acknowledgment->acknowledgmentTime == Time::Min())
+    if (!m_txParams.m_acknowledgment->acknowledgmentTime.has_value())
     {
         CalculateAcknowledgmentTime(m_txParams.m_acknowledgment.get());
     }
@@ -1143,9 +1151,9 @@
     NS_LOG_FUNCTION(this << *mpdu << &txParams << ppduDurationLimit);
 
     Mac48Address receiver = mpdu->GetHeader().GetAddr1();
-    uint32_t ampduSize = txParams.GetSizeIfAddMpdu(mpdu);
+    uint32_t ampduSize = txParams.GetSize(receiver);
 
-    if (txParams.GetSize(receiver) > 0)
+    if (!txParams.LastAddedIsFirstMpdu(receiver))
     {
         // we are attempting to perform A-MPDU aggregation, hence we have to check
         // that we meet the limit on the max A-MPDU size
@@ -1210,9 +1218,14 @@
     NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
     NS_LOG_FUNCTION(this << *msdu << &txParams << availableTime);
 
+    // tentatively aggregate the given MPDU
+    auto prevTxDuration = txParams.m_txDuration;
+    txParams.AggregateMsdu(msdu);
+    UpdateTxDuration(msdu->GetHeader().GetAddr1(), txParams);
+
     // check if aggregating the given MSDU requires a different protection method
     NS_ASSERT(txParams.m_protection);
-    Time protectionTime = txParams.m_protection->protectionTime;
+    auto protectionTime = txParams.m_protection->protectionTime;
 
     std::unique_ptr<WifiProtection> protection;
     protection = GetProtectionManager()->TryAggregateMsdu(msdu, txParams);
@@ -1228,11 +1241,11 @@
         txParams.m_protection.swap(protection);
         protectionSwapped = true;
     }
-    NS_ASSERT(protectionTime != Time::Min());
+    NS_ASSERT(protectionTime.has_value());
 
     // check if aggregating the given MSDU requires a different acknowledgment method
     NS_ASSERT(txParams.m_acknowledgment);
-    Time acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
+    auto acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
 
     std::unique_ptr<WifiAcknowledgment> acknowledgment;
     acknowledgment = GetAckManager()->TryAggregateMsdu(msdu, txParams);
@@ -1248,18 +1261,20 @@
         txParams.m_acknowledgment.swap(acknowledgment);
         acknowledgmentSwapped = true;
     }
-    NS_ASSERT(acknowledgmentTime != Time::Min());
+    NS_ASSERT(acknowledgmentTime.has_value());
 
     Time ppduDurationLimit = Time::Min();
     if (availableTime != Time::Min())
     {
-        ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
+        ppduDurationLimit = availableTime - *protectionTime - *acknowledgmentTime;
     }
 
     if (!IsWithinLimitsIfAggregateMsdu(msdu, txParams, ppduDurationLimit))
     {
-        // adding MPDU failed, restore protection and acknowledgment methods
-        // if they were swapped
+        // adding MPDU failed, undo the addition of the MPDU and restore protection and
+        // acknowledgment methods if they were swapped
+        txParams.UndoAddMpdu();
+        txParams.m_txDuration = prevTxDuration;
         if (protectionSwapped)
         {
             txParams.m_protection.swap(protection);
@@ -1271,10 +1286,6 @@
         return false;
     }
 
-    // the given MPDU can be added, hence update the txParams
-    txParams.AggregateMsdu(msdu);
-    UpdateTxDuration(msdu->GetHeader().GetAddr1(), txParams);
-
     return true;
 }
 
@@ -1286,10 +1297,11 @@
     NS_ASSERT(msdu && msdu->GetHeader().IsQosData());
     NS_LOG_FUNCTION(this << *msdu << &txParams << ppduDurationLimit);
 
-    std::pair<uint16_t, uint32_t> ret = txParams.GetSizeIfAggregateMsdu(msdu);
-    Mac48Address receiver = msdu->GetHeader().GetAddr1();
-    uint8_t tid = msdu->GetHeader().GetQosTid();
-    WifiModulationClass modulation = txParams.m_txVector.GetModulationClass();
+    auto receiver = msdu->GetHeader().GetAddr1();
+    auto tid = msdu->GetHeader().GetQosTid();
+    auto modulation = txParams.m_txVector.GetModulationClass();
+    auto psduInfo = txParams.GetPsduInfo(receiver);
+    NS_ASSERT_MSG(psduInfo, "No PSDU info for receiver " << receiver);
 
     // Check that the limit on A-MSDU size is met
     uint16_t maxAmsduSize = m_msduAggregator->GetMaxAmsduSize(receiver, tid, modulation);
@@ -1300,7 +1312,7 @@
         return false;
     }
 
-    if (ret.first > maxAmsduSize)
+    if (psduInfo->amsduSize > maxAmsduSize)
     {
         NS_LOG_DEBUG("No other MSDU can be aggregated: maximum A-MSDU size (" << maxAmsduSize
                                                                               << ") reached ");
@@ -1309,18 +1321,19 @@
 
     const WifiTxParameters::PsduInfo* info = txParams.GetPsduInfo(msdu->GetHeader().GetAddr1());
     NS_ASSERT(info);
+    auto ampduSize = txParams.GetSize(receiver);
 
     if (info->ampduSize > 0)
     {
         // the A-MSDU being built is aggregated to other MPDUs in an A-MPDU.
         // Check that the limit on A-MPDU size is met.
-        if (!IsWithinAmpduSizeLimit(ret.second, receiver, tid, modulation))
+        if (!IsWithinAmpduSizeLimit(ampduSize, receiver, tid, modulation))
         {
             return false;
         }
     }
 
-    return IsWithinSizeAndTimeLimits(ret.second, receiver, txParams, ppduDurationLimit);
+    return IsWithinSizeAndTimeLimits(ampduSize, receiver, txParams, ppduDurationLimit);
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/ht/ht-phy.cc ns-3.42/src/wifi/model/ht/ht-phy.cc
--- ns-3.41/src/wifi/model/ht/ht-phy.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/ht/ht-phy.cc	2024-05-29 15:29:47.204074000 -0700
@@ -29,6 +29,9 @@
 #include "ns3/wifi-psdu.h"
 #include "ns3/wifi-utils.h"
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
@@ -821,7 +824,6 @@
 PhyEntity::CcaIndication
 HtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
 {
-    NS_LOG_FUNCTION(this);
     if (m_wifiPhy->GetChannelWidth() < 40)
     {
         return OfdmPhy::GetCcaIndication(ppdu);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/interference-helper.cc ns-3.42/src/wifi/model/interference-helper.cc
--- ns-3.41/src/wifi/model/interference-helper.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/interference-helper.cc	2024-05-29 15:29:47.204074000 -0700
@@ -174,8 +174,7 @@
 
 InterferenceHelper::InterferenceHelper()
     : m_errorRateModel(nullptr),
-      m_numRxAntennas(1),
-      m_rxing(false)
+      m_numRxAntennas(1)
 {
     NS_LOG_FUNCTION(this);
 }
@@ -212,15 +211,18 @@
 InterferenceHelper::Add(Ptr<const WifiPpdu> ppdu,
                         Time duration,
                         RxPowerWattPerChannelBand& rxPowerW,
+                        const FrequencyRange& freqRange,
                         bool isStartHePortionRxing)
 {
     Ptr<Event> event = Create<Event>(ppdu, duration, std::move(rxPowerW));
-    AppendEvent(event, isStartHePortionRxing);
+    AppendEvent(event, freqRange, isStartHePortionRxing);
     return event;
 }
 
 void
-InterferenceHelper::AddForeignSignal(Time duration, RxPowerWattPerChannelBand& rxPowerW)
+InterferenceHelper::AddForeignSignal(Time duration,
+                                     RxPowerWattPerChannelBand& rxPowerW,
+                                     const FrequencyRange& freqRange)
 {
     // Parameters other than duration and rxPowerW are unused for this type
     // of signal, so we provide dummy versions
@@ -230,7 +232,7 @@
     Ptr<WifiPpdu> fakePpdu = Create<WifiPpdu>(Create<WifiPsdu>(Create<Packet>(0), hdr),
                                               WifiTxVector(),
                                               WifiPhyOperatingChannel());
-    Add(fakePpdu, duration, rxPowerW);
+    Add(fakePpdu, duration, rxPowerW, freqRange);
 }
 
 bool
@@ -242,15 +244,15 @@
 bool
 InterferenceHelper::HasBand(const WifiSpectrumBandInfo& band) const
 {
-    return (m_niChanges.count(band) > 0);
+    return m_niChanges.contains(band);
 }
 
 void
 InterferenceHelper::AddBand(const WifiSpectrumBandInfo& band)
 {
     NS_LOG_FUNCTION(this << band);
-    NS_ASSERT(m_niChanges.count(band) == 0);
-    NS_ASSERT(m_firstPowers.count(band) == 0);
+    NS_ASSERT(!m_niChanges.contains(band));
+    NS_ASSERT(!m_firstPowers.contains(band));
     NiChanges niChanges;
     auto result = m_niChanges.insert({band, niChanges});
     NS_ASSERT(result.second);
@@ -344,9 +346,11 @@
 }
 
 void
-InterferenceHelper::AppendEvent(Ptr<Event> event, bool isStartHePortionRxing)
+InterferenceHelper::AppendEvent(Ptr<Event> event,
+                                const FrequencyRange& freqRange,
+                                bool isStartHePortionRxing)
 {
-    NS_LOG_FUNCTION(this << event << isStartHePortionRxing);
+    NS_LOG_FUNCTION(this << event << freqRange << isStartHePortionRxing);
     for (const auto& [band, power] : event->GetRxPowerWPerBand())
     {
         auto niIt = m_niChanges.find(band);
@@ -356,7 +360,7 @@
         auto previousPowerPosition = GetPreviousPosition(event->GetStartTime(), niIt);
         previousPowerStart = previousPowerPosition->second.GetPower();
         previousPowerEnd = GetPreviousPosition(event->GetEndTime(), niIt)->second.GetPower();
-        if (!m_rxing)
+        if (const auto rxing = (m_rxing.contains(freqRange) && m_rxing.at(freqRange)); !rxing)
         {
             m_firstPowers.find(band)->second = previousPowerStart;
             // Always leave the first zero power noise event in the list
@@ -413,9 +417,9 @@
     double noiseFloor = m_noiseFigure * Nt;
     double noise = noiseFloor + noiseInterference;
     double snr = signal / noise; // linear scale
-    NS_LOG_DEBUG("bandwidth(MHz)=" << channelWidth << ", signal(W)= " << signal << ", noise(W)="
-                                   << noiseFloor << ", interference(W)=" << noiseInterference
-                                   << ", snr=" << RatioToDb(snr) << "dB");
+    NS_LOG_DEBUG("bandwidth=" << channelWidth << "MHz, signal=" << signal << "W, noise="
+                              << noiseFloor << "W, interference=" << noiseInterference
+                              << "W, snr=" << RatioToDb(snr) << "dB");
     if (m_errorRateModel->IsAwgn())
     {
         double gain = 1;
@@ -441,11 +445,12 @@
     double noiseInterferenceW = firstPower_it->second;
     auto niIt = m_niChanges.find(band);
     NS_ABORT_IF(niIt == m_niChanges.end());
+    const auto now = Simulator::Now();
     auto it = niIt->second.find(event->GetStartTime());
     double muMimoPowerW = (event->GetPpdu()->GetType() == WIFI_PPDU_TYPE_UL_MU)
                               ? CalculateMuMimoPowerW(event, band)
                               : 0.0;
-    for (; it != niIt->second.end() && it->first < Simulator::Now(); ++it)
+    for (; it != niIt->second.end() && it->first < now; ++it)
     {
         if (IsSameMuMimoTransmission(event, it->second.GetEvent()) &&
             (event != it->second.GetEvent()))
@@ -589,7 +594,7 @@
     }
     Time windowStart = phyPayloadStart + window.first;
     Time windowEnd = phyPayloadStart + window.second;
-    NS_ABORT_IF(m_firstPowers.count(band) == 0);
+    NS_ABORT_IF(!m_firstPowers.contains(band));
     double noiseInterferenceW = m_firstPowers.at(band);
     double powerW = event->GetRxPowerW(band);
     while (++j != niIt.cend())
@@ -663,7 +668,7 @@
     }
 
     Time previous = j->first;
-    NS_ABORT_IF(m_firstPowers.count(band) == 0);
+    NS_ABORT_IF(!m_firstPowers.contains(band));
     double noiseInterferenceW = m_firstPowers.at(band);
     double powerW = event->GetRxPowerW(band);
     while (++j != niIt.end())
@@ -814,17 +819,17 @@
 }
 
 void
-InterferenceHelper::NotifyRxStart()
+InterferenceHelper::NotifyRxStart(const FrequencyRange& freqRange)
 {
-    NS_LOG_FUNCTION(this);
-    m_rxing = true;
+    NS_LOG_FUNCTION(this << freqRange);
+    m_rxing[freqRange] = true;
 }
 
 void
 InterferenceHelper::NotifyRxEnd(Time endTime, const FrequencyRange& freqRange)
 {
     NS_LOG_FUNCTION(this << endTime << freqRange);
-    m_rxing = false;
+    m_rxing.at(freqRange) = false;
     // Update m_firstPowers for frame capture
     for (auto niIt = m_niChanges.begin(); niIt != m_niChanges.end(); ++niIt)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/interference-helper.h ns-3.42/src/wifi/model/interference-helper.h
--- ns-3.41/src/wifi/model/interference-helper.h	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/interference-helper.h	2024-05-29 15:29:47.204074000 -0700
@@ -208,6 +208,7 @@
      * \param ppdu the PPDU
      * \param duration the PPDU duration
      * \param rxPower received power per band (W)
+     * \param freqRange the frequency range in which the received signal is detected
      * \param isStartHePortionRxing flag whether the event corresponds to the start of the HE
      * portion reception (only used for MU)
      *
@@ -216,14 +217,18 @@
     Ptr<Event> Add(Ptr<const WifiPpdu> ppdu,
                    Time duration,
                    RxPowerWattPerChannelBand& rxPower,
+                   const FrequencyRange& freqRange,
                    bool isStartHePortionRxing = false);
 
     /**
      * Add a non-Wifi signal to interference helper.
      * \param duration the duration of the signal
      * \param rxPower received power per band (W)
+     * \param freqRange the frequency range in which the received signal is detected
      */
-    void AddForeignSignal(Time duration, RxPowerWattPerChannelBand& rxPower);
+    void AddForeignSignal(Time duration,
+                          RxPowerWattPerChannelBand& rxPower,
+                          const FrequencyRange& freqRange);
     /**
      * Calculate the SNIR at the start of the payload and accumulate
      * all SNIR changes in the SNIR vector for each MPDU of an A-MPDU.
@@ -277,13 +282,14 @@
 
     /**
      * Notify that RX has started.
+     * \param freqRange the frequency range in which the received signal event is detected
      */
-    void NotifyRxStart();
+    void NotifyRxStart(const FrequencyRange& freqRange);
     /**
      * Notify that RX has ended.
      *
      * \param endTime the end time of the signal
-     * \param freqRange the frequency range in which the received signal event had been detected
+     * \param freqRange the frequency range in which the received signal event was detected
      */
     void NotifyRxEnd(Time endTime, const FrequencyRange& freqRange);
 
@@ -346,6 +352,10 @@
                                             const WifiTxVector& txVector,
                                             uint16_t staId = SU_STA_ID) const;
 
+  protected:
+    std::map<FrequencyRange, bool>
+        m_rxing; //!< flag whether it is in receiving state for a given FrequencyRange
+
   private:
     /**
      * Noise and Interference (thus Ni) event.
@@ -422,10 +432,11 @@
      * Append the given Event.
      *
      * \param event the event to be appended
+     * \param freqRange the frequency range in which the received signal event is detected
      * \param isStartHePortionRxing flag whether event corresponds to the start of the HE portion
      * reception (only used for MU)
      */
-    void AppendEvent(Ptr<Event> event, bool isStartHePortionRxing);
+    void AppendEvent(Ptr<Event> event, const FrequencyRange& freqRange, bool isStartHePortionRxing);
 
     /**
      * Calculate noise and interference power in W.
@@ -511,7 +522,6 @@
     uint8_t m_numRxAntennas;         //!< the number of RX antennas in the corresponding receiver
     NiChangesPerBand m_niChanges;    //!< NI Changes for each band
     FirstPowerPerBand m_firstPowers; //!< first power of each band in watts
-    bool m_rxing;                    //!< flag whether it is in receiving state
 
     /**
      * Returns an iterator to the first NiChange that is later than moment
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/mac-rx-middle.cc ns-3.42/src/wifi/model/mac-rx-middle.cc
--- ns-3.41/src/wifi/model/mac-rx-middle.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/mac-rx-middle.cc	2024-05-29 15:29:47.204074000 -0700
@@ -58,11 +58,6 @@
         m_defragmenting = false;
     }
 
-    ~OriginatorRxStatus()
-    {
-        m_fragments.clear();
-    }
-
     /**
      * Check if we are de-fragmenting packets.
      *
@@ -167,16 +162,6 @@
 MacRxMiddle::~MacRxMiddle()
 {
     NS_LOG_FUNCTION_NOARGS();
-    for (auto i = m_originatorStatus.begin(); i != m_originatorStatus.end(); i++)
-    {
-        delete (*i).second;
-    }
-    m_originatorStatus.erase(m_originatorStatus.begin(), m_originatorStatus.end());
-    for (auto i = m_qosOriginatorStatus.begin(); i != m_qosOriginatorStatus.end(); i++)
-    {
-        delete (*i).second;
-    }
-    m_qosOriginatorStatus.erase(m_qosOriginatorStatus.begin(), m_qosOriginatorStatus.end());
 }
 
 void
@@ -186,63 +171,51 @@
     m_callback = callback;
 }
 
-OriginatorRxStatus*
-MacRxMiddle::Lookup(const WifiMacHeader* hdr)
+OriginatorRxStatus&
+MacRxMiddle::Lookup(const WifiMacHeader& hdr)
 {
     NS_LOG_FUNCTION(hdr);
-    OriginatorRxStatus* originator;
-    Mac48Address source = hdr->GetAddr2();
-    if (hdr->IsQosData() && !hdr->GetAddr2().IsGroup())
+    const auto source = hdr.GetAddr2();
+    if (hdr.IsQosData() && !source.IsGroup())
     {
         /* only for QoS data non-broadcast frames */
-        originator = m_qosOriginatorStatus[std::make_pair(source, hdr->GetQosTid())];
-        if (originator == nullptr)
-        {
-            originator = new OriginatorRxStatus();
-            m_qosOriginatorStatus[std::make_pair(source, hdr->GetQosTid())] = originator;
-        }
-    }
-    else
-    {
-        /* - management frames
-         * - QoS data broadcast frames
-         * - non-QoS data frames
-         * see section 7.1.3.4.1
-         */
-        originator = m_originatorStatus[source];
-        if (originator == nullptr)
-        {
-            originator = new OriginatorRxStatus();
-            m_originatorStatus[source] = originator;
-        }
-    }
-    return originator;
+        const auto key = std::make_pair(source, hdr.GetQosTid());
+        auto [it, inserted] = m_qosOriginatorStatus.try_emplace(key);
+        return it->second;
+    }
+    /* - management frames
+     * - QoS data broadcast frames
+     * - non-QoS data frames
+     * see section 7.1.3.4.1
+     */
+    auto [it, inserted] = m_originatorStatus.try_emplace(source);
+    return it->second;
 }
 
 bool
-MacRxMiddle::IsDuplicate(const WifiMacHeader* hdr, OriginatorRxStatus* originator) const
+MacRxMiddle::IsDuplicate(const WifiMacHeader& hdr, const OriginatorRxStatus& originator) const
 {
-    NS_LOG_FUNCTION(hdr << originator);
-    return hdr->IsRetry() && originator->GetLastSequenceControl() == hdr->GetSequenceControl();
+    NS_LOG_FUNCTION(hdr << &originator);
+    return hdr.IsRetry() && originator.GetLastSequenceControl() == hdr.GetSequenceControl();
 }
 
 Ptr<const Packet>
 MacRxMiddle::HandleFragments(Ptr<const Packet> packet,
-                             const WifiMacHeader* hdr,
-                             OriginatorRxStatus* originator)
+                             const WifiMacHeader& hdr,
+                             OriginatorRxStatus& originator)
 {
-    NS_LOG_FUNCTION(packet << hdr << originator);
-    if (originator->IsDeFragmenting())
+    NS_LOG_FUNCTION(packet << hdr << &originator);
+    if (originator.IsDeFragmenting())
     {
-        if (hdr->IsMoreFragments())
+        if (hdr.IsMoreFragments())
         {
-            if (originator->IsNextFragment(hdr->GetSequenceControl()))
+            if (originator.IsNextFragment(hdr.GetSequenceControl()))
             {
-                NS_LOG_DEBUG("accumulate fragment seq=" << hdr->GetSequenceNumber()
-                                                        << ", frag=" << +hdr->GetFragmentNumber()
+                NS_LOG_DEBUG("accumulate fragment seq=" << hdr.GetSequenceNumber()
+                                                        << ", frag=" << +hdr.GetFragmentNumber()
                                                         << ", size=" << packet->GetSize());
-                originator->AccumulateFragment(packet);
-                originator->SetSequenceControl(hdr->GetSequenceControl());
+                originator.AccumulateFragment(packet);
+                originator.SetSequenceControl(hdr.GetSequenceControl());
             }
             else
             {
@@ -252,13 +225,13 @@
         }
         else
         {
-            if (originator->IsNextFragment(hdr->GetSequenceControl()))
+            if (originator.IsNextFragment(hdr.GetSequenceControl()))
             {
-                NS_LOG_DEBUG("accumulate last fragment seq="
-                             << hdr->GetSequenceNumber() << ", frag=" << +hdr->GetFragmentNumber()
-                             << ", size=" << hdr->GetSize());
-                Ptr<Packet> p = originator->AccumulateLastFragment(packet);
-                originator->SetSequenceControl(hdr->GetSequenceControl());
+                NS_LOG_DEBUG("accumulate last fragment seq=" << hdr.GetSequenceNumber() << ", frag="
+                                                             << +hdr.GetFragmentNumber()
+                                                             << ", size=" << hdr.GetSize());
+                Ptr<Packet> p = originator.AccumulateLastFragment(packet);
+                originator.SetSequenceControl(hdr.GetSequenceControl());
                 return p;
             }
             else
@@ -270,13 +243,13 @@
     }
     else
     {
-        if (hdr->IsMoreFragments())
+        if (hdr.IsMoreFragments())
         {
-            NS_LOG_DEBUG("accumulate first fragment seq=" << hdr->GetSequenceNumber()
-                                                          << ", frag=" << +hdr->GetFragmentNumber()
+            NS_LOG_DEBUG("accumulate first fragment seq=" << hdr.GetSequenceNumber()
+                                                          << ", frag=" << +hdr.GetFragmentNumber()
                                                           << ", size=" << packet->GetSize());
-            originator->AccumulateFirstFragment(packet);
-            originator->SetSequenceControl(hdr->GetSequenceControl());
+            originator.AccumulateFirstFragment(packet);
+            originator.SetSequenceControl(hdr.GetSequenceControl());
             return nullptr;
         }
         else
@@ -291,10 +264,10 @@
 {
     NS_LOG_FUNCTION(*mpdu << +linkId);
     // consider the MAC header of the original MPDU (makes a difference for data frames only)
-    const WifiMacHeader* hdr = &mpdu->GetOriginal()->GetHeader();
-    NS_ASSERT(hdr->IsData() || hdr->IsMgt());
+    const auto& hdr = mpdu->GetOriginal()->GetHeader();
+    NS_ASSERT(hdr.IsData() || hdr.IsMgt());
 
-    OriginatorRxStatus* originator = Lookup(hdr);
+    auto& originator = Lookup(hdr);
     /**
      * The check below is really unneeded because it can fail in a lot of
      * normal cases. Specifically, it is possible for sequence numbers to
@@ -304,18 +277,18 @@
      * So, this check cannot be used to discard old duplicate frames. It is
      * thus here only for documentation purposes.
      */
-    if (!(SequenceNumber16(originator->GetLastSequenceControl()) <
-          SequenceNumber16(hdr->GetSequenceControl())))
+    if (!(SequenceNumber16(originator.GetLastSequenceControl()) <
+          SequenceNumber16(hdr.GetSequenceControl())))
     {
         NS_LOG_DEBUG("Sequence numbers have looped back. last recorded="
-                     << originator->GetLastSequenceControl()
-                     << " currently seen=" << hdr->GetSequenceControl());
+                     << originator.GetLastSequenceControl()
+                     << " currently seen=" << hdr.GetSequenceControl());
     }
     // filter duplicates.
     if (IsDuplicate(hdr, originator))
     {
-        NS_LOG_DEBUG("duplicate from=" << hdr->GetAddr2() << ", seq=" << hdr->GetSequenceNumber()
-                                       << ", frag=" << +hdr->GetFragmentNumber());
+        NS_LOG_DEBUG("duplicate from=" << hdr.GetAddr2() << ", seq=" << hdr.GetSequenceNumber()
+                                       << ", frag=" << +hdr.GetFragmentNumber());
         return;
     }
     Ptr<const Packet> aggregate = HandleFragments(mpdu->GetPacket(), hdr, originator);
@@ -323,11 +296,11 @@
     {
         return;
     }
-    NS_LOG_DEBUG("forwarding data from=" << hdr->GetAddr2() << ", seq=" << hdr->GetSequenceNumber()
-                                         << ", frag=" << +hdr->GetFragmentNumber());
-    if (!hdr->GetAddr1().IsGroup())
+    NS_LOG_DEBUG("forwarding data from=" << hdr.GetAddr2() << ", seq=" << hdr.GetSequenceNumber()
+                                         << ", frag=" << +hdr.GetFragmentNumber());
+    if (!hdr.GetAddr1().IsGroup())
     {
-        originator->SetSequenceControl(hdr->GetSequenceControl());
+        originator.SetSequenceControl(hdr.GetSequenceControl());
     }
     if (aggregate == mpdu->GetPacket())
     {
@@ -339,7 +312,7 @@
         // A-MSDUs saves us the time to deaggregate the A-MSDU in MSDUs (which are
         // kept separate in the received mpdu) and allows us to pass the originally
         // transmitted packets (i.e., with the same UID) to the receiver.
-        m_callback(Create<WifiMpdu>(aggregate, *hdr), linkId);
+        m_callback(Create<WifiMpdu>(aggregate, hdr), linkId);
     }
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/mac-rx-middle.h ns-3.42/src/wifi/model/mac-rx-middle.h
--- ns-3.41/src/wifi/model/mac-rx-middle.h	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/mac-rx-middle.h	2024-05-29 15:29:47.204074000 -0700
@@ -45,7 +45,7 @@
     /**
      * typedef for callback
      */
-    typedef Callback<void, Ptr<const WifiMpdu>, uint8_t /* link ID */> ForwardUpCallback;
+    using ForwardUpCallback = Callback<void, Ptr<const WifiMpdu>, uint8_t /* link ID */>;
 
     MacRxMiddle();
     ~MacRxMiddle();
@@ -77,7 +77,7 @@
      *
      * \return OriginatorRxStatus
      */
-    OriginatorRxStatus* Lookup(const WifiMacHeader* hdr);
+    OriginatorRxStatus& Lookup(const WifiMacHeader& hdr);
     /**
      * Check if we have already received the packet from the sender before
      * (by looking at the sequence control field).
@@ -88,7 +88,7 @@
      * \return true if we already received the packet previously,
      *         false otherwise
      */
-    bool IsDuplicate(const WifiMacHeader* hdr, OriginatorRxStatus* originator) const;
+    bool IsDuplicate(const WifiMacHeader& hdr, const OriginatorRxStatus& originator) const;
     /**
      * Check if the received packet is a fragment and handle it appropriately.
      * If the packet is not a fragment, the method returns the packet.
@@ -105,27 +105,30 @@
      *         0 if we failed to reassemble the packet (e.g. missing fragments/out-of-order).
      */
     Ptr<const Packet> HandleFragments(Ptr<const Packet> packet,
-                                      const WifiMacHeader* hdr,
-                                      OriginatorRxStatus* originator);
+                                      const WifiMacHeader& hdr,
+                                      OriginatorRxStatus& originator);
 
     /**
      * typedef for a map between address and OriginatorRxStatus
      */
-    typedef std::map<Mac48Address, OriginatorRxStatus*, std::less<>> Originators;
+    using Originators = std::map<Mac48Address, OriginatorRxStatus, std::less<>>;
+
     /**
      * typedef for a map between address, OriginatorRxStatus, and Traffic ID
      */
-    typedef std::map<std::pair<Mac48Address, uint8_t>, OriginatorRxStatus*, std::less<>>
-        QosOriginators;
+    using QosOriginators =
+        std::map<std::pair<Mac48Address, uint8_t>, OriginatorRxStatus, std::less<>>;
+
     /**
      * typedef for an iterator for Originators
      */
-    typedef std::map<Mac48Address, OriginatorRxStatus*, std::less<>>::iterator OriginatorsI;
+    using OriginatorsI = std::map<Mac48Address, OriginatorRxStatus, std::less<>>::iterator;
+
     /**
      * typedef for an iterator for QosOriginators
      */
-    typedef std::map<std::pair<Mac48Address, uint8_t>, OriginatorRxStatus*, std::less<>>::iterator
-        QosOriginatorsI;
+    using QosOriginatorsI =
+        std::map<std::pair<Mac48Address, uint8_t>, OriginatorRxStatus, std::less<>>::iterator;
 
     Originators m_originatorStatus;       ///< originator status
     QosOriginators m_qosOriginatorStatus; ///< QOS originator status
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/mgt-action-headers.cc ns-3.42/src/wifi/model/mgt-action-headers.cc
--- ns-3.41/src/wifi/model/mgt-action-headers.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/mgt-action-headers.cc	2024-05-29 15:29:47.204074000 -0700
@@ -25,6 +25,9 @@
 
 #include "ns3/multi-link-element.h"
 #include "ns3/packet.h"
+#include "ns3/simulator.h"
+
+#include <vector>
 
 namespace ns3
 {
@@ -191,6 +194,9 @@
         case QAB_RESPONSE:
             retval.publicAction = QAB_RESPONSE;
             break;
+        case FILS_DISCOVERY:
+            retval.publicAction = FILS_DISCOVERY;
+            break;
         default:
             NS_FATAL_ERROR("Unknown public action code");
             retval.publicAction = QAB_REQUEST; /* quiet compiler */
@@ -293,9 +299,7 @@
     case MULTIHOP: // not yet supported
         switch (m_actionValue)
         {
-        case PROXY_UPDATE: // not used so far
-            retval.multihopAction = PROXY_UPDATE;
-            break;
+        case PROXY_UPDATE:              // not used so far
         case PROXY_UPDATE_CONFIRMATION: // not used so far
             retval.multihopAction = PROXY_UPDATE;
             break;
@@ -553,6 +557,7 @@
         {
             CASE_ACTION_VALUE(QAB_REQUEST);
             CASE_ACTION_VALUE(QAB_RESPONSE);
+            CASE_ACTION_VALUE(FILS_DISCOVERY);
         default:
             NS_FATAL_ERROR("Unknown public action code");
         }
@@ -1349,4 +1354,411 @@
     return list;
 }
 
+/***************************************************
+ *                 FILS Discovery
+ ****************************************************/
+
+NS_OBJECT_ENSURE_REGISTERED(FilsDiscHeader);
+
+TypeId
+FilsDiscHeader::GetTypeId()
+{
+    static TypeId tid = TypeId("ns3::FilsDiscHeader")
+                            .SetParent<Header>()
+                            .SetGroupName("Wifi")
+                            .AddConstructor<FilsDiscHeader>();
+    return tid;
+}
+
+TypeId
+FilsDiscHeader::GetInstanceTypeId() const
+{
+    return GetTypeId();
+}
+
+FilsDiscHeader::FilsDiscHeader()
+    : m_len(m_frameCtl.m_lenPresenceInd),
+      m_fdCap(m_frameCtl.m_capPresenceInd),
+      m_primaryCh(m_frameCtl.m_primChPresenceInd),
+      m_apConfigSeqNum(m_frameCtl.m_apCsnPresenceInd),
+      m_accessNetOpt(m_frameCtl.m_anoPresenceInd),
+      m_chCntrFreqSeg1(m_frameCtl.m_chCntrFreqSeg1PresenceInd)
+{
+}
+
+void
+FilsDiscHeader::SetSsid(const std::string& ssid)
+{
+    m_ssid = ssid;
+    m_frameCtl.m_ssidLen = ssid.length() - 1;
+}
+
+const std::string&
+FilsDiscHeader::GetSsid() const
+{
+    return m_ssid;
+}
+
+uint32_t
+FilsDiscHeader::GetInformationFieldSize() const
+{
+    auto size = GetSizeNonOptSubfields();
+    size += m_len.has_value() ? 1 : 0;
+    size += m_fdCap.has_value() ? 2 : 0;
+    size += m_opClass.has_value() ? 1 : 0;
+    size += m_primaryCh.has_value() ? 1 : 0;
+    size += m_apConfigSeqNum.has_value() ? 1 : 0;
+    size += m_accessNetOpt.has_value() ? 1 : 0;
+    size += m_chCntrFreqSeg1.has_value() ? 1 : 0;
+    return size;
+}
+
+uint32_t
+FilsDiscHeader::GetSerializedSize() const
+{
+    auto size = GetInformationFieldSize();
+    // Optional elements
+    size += m_rnr.has_value() ? m_rnr->GetSerializedSize() : 0;
+    size += m_tim.has_value() ? m_tim->GetSerializedSize() : 0;
+    return size;
+}
+
+uint32_t
+FilsDiscHeader::GetSizeNonOptSubfields() const
+{
+    return 2                  /* FILS Discovery Frame Control */
+           + 8                /* Timestamp */
+           + 2                /* Beacon Interval */
+           + m_ssid.length(); /* SSID */
+}
+
+void
+FilsDiscHeader::SetLengthSubfield()
+{
+    m_len.reset(); // so that Length size is not included by GetInformationFieldSize()
+    auto infoFieldSize = GetInformationFieldSize();
+    auto nonOptSubfieldsSize = GetSizeNonOptSubfields();
+    NS_ABORT_MSG_IF(infoFieldSize < nonOptSubfieldsSize, "Length subfield is less than 0");
+    m_len = infoFieldSize - nonOptSubfieldsSize;
+}
+
+void
+FilsDiscHeader::Print(std::ostream& os) const
+{
+    os << "Control=" << m_frameCtl << ", "
+       << "Time Stamp=" << m_timeStamp << ", "
+       << "Beacon Interval=" << m_beaconInt << ", "
+       << "SSID=" << m_ssid << ", ";
+    if (m_len.has_value())
+    {
+        os << "Length=" << *m_len << ", ";
+    }
+    if (m_fdCap.has_value())
+    {
+        os << "FD Capability=" << *m_fdCap << ", ";
+    }
+    if (m_opClass.has_value())
+    {
+        os << "Operating Class=" << *m_opClass << ", ";
+    }
+    if (m_primaryCh.has_value())
+    {
+        os << "Primary Channel=" << *m_primaryCh << ", ";
+    }
+    if (m_apConfigSeqNum.has_value())
+    {
+        os << "AP-CSN=" << *m_apConfigSeqNum << ", ";
+    }
+    if (m_accessNetOpt.has_value())
+    {
+        os << "ANO=" << *m_accessNetOpt << ", ";
+    }
+    if (m_chCntrFreqSeg1.has_value())
+    {
+        os << "Channel Center Frequency Seg 1=" << *m_chCntrFreqSeg1 << ", ";
+    }
+    if (m_tim.has_value())
+    {
+        os << "Traffic Indicator Map=" << *m_tim;
+    }
+}
+
+void
+FilsDiscHeader::Serialize(Buffer::Iterator start) const
+{
+    Buffer::Iterator i = start;
+    m_frameCtl.Serialize(i);
+    i.WriteHtolsbU64(Simulator::Now().GetMicroSeconds()); // Time stamp
+    i.WriteHtolsbU16(m_beaconInt);
+    i.Write(reinterpret_cast<const uint8_t*>(m_ssid.data()), m_ssid.length());
+    if (m_len.has_value())
+    {
+        i.WriteU8(*m_len);
+    }
+    if (m_fdCap.has_value())
+    {
+        m_fdCap->Serialize(i);
+    }
+    NS_ASSERT(m_opClass.has_value() == m_primaryCh.has_value());
+    if (m_opClass.has_value())
+    {
+        i.WriteU8(*m_opClass);
+    }
+    if (m_primaryCh.has_value())
+    {
+        i.WriteU8(*m_primaryCh);
+    }
+    if (m_apConfigSeqNum.has_value())
+    {
+        i.WriteU8(*m_apConfigSeqNum);
+    }
+    if (m_accessNetOpt.has_value())
+    {
+        i.WriteU8(*m_accessNetOpt);
+    }
+    if (m_chCntrFreqSeg1.has_value())
+    {
+        i.WriteU8(*m_chCntrFreqSeg1);
+    }
+    i = m_rnr.has_value() ? m_rnr->Serialize(i) : i;
+    i = m_tim.has_value() ? m_tim->Serialize(i) : i;
+}
+
+uint32_t
+FilsDiscHeader::Deserialize(Buffer::Iterator start)
+{
+    Buffer::Iterator i = start;
+    auto nOctets = m_frameCtl.Deserialize(i);
+    i.Next(nOctets);
+    m_timeStamp = i.ReadLsbtohU64();
+    m_beaconInt = i.ReadLsbtohU16();
+    std::vector<uint8_t> ssid(m_frameCtl.m_ssidLen + 2);
+    i.Read(ssid.data(), m_frameCtl.m_ssidLen + 1);
+    ssid[m_frameCtl.m_ssidLen + 1] = 0;
+    m_ssid = std::string(reinterpret_cast<char*>(ssid.data()));
+    // Optional subfields
+    if (m_frameCtl.m_lenPresenceInd)
+    {
+        m_len = i.ReadU8();
+    }
+    if (m_frameCtl.m_capPresenceInd)
+    {
+        nOctets = m_fdCap->Deserialize(i);
+        i.Next(nOctets);
+    }
+    if (m_frameCtl.m_primChPresenceInd)
+    {
+        m_opClass = i.ReadU8();
+        m_primaryCh = i.ReadU8();
+    }
+    if (m_frameCtl.m_apCsnPresenceInd)
+    {
+        m_apConfigSeqNum = i.ReadU8();
+    }
+    if (m_frameCtl.m_anoPresenceInd)
+    {
+        m_accessNetOpt = i.ReadU8();
+    }
+    if (m_frameCtl.m_chCntrFreqSeg1PresenceInd)
+    {
+        m_chCntrFreqSeg1 = i.ReadU8();
+    }
+    // Optional elements
+    m_rnr.emplace();
+    auto tmp = i;
+    i = m_rnr->DeserializeIfPresent(i);
+    if (i.GetDistanceFrom(tmp) == 0)
+    {
+        m_rnr.reset();
+    }
+
+    m_tim.emplace();
+    tmp = i;
+    i = m_tim->DeserializeIfPresent(i);
+    if (i.GetDistanceFrom(tmp) == 0)
+    {
+        m_tim.reset();
+    }
+
+    return i.GetDistanceFrom(start);
+}
+
+std::ostream&
+operator<<(std::ostream& os, const FilsDiscHeader::FilsDiscFrameControl& control)
+{
+    os << "ssidLen:" << control.m_ssidLen << " capPresenceInd:" << control.m_capPresenceInd
+       << " shortSsidInd:" << control.m_shortSsidInd
+       << " apCsnPresenceInd:" << control.m_apCsnPresenceInd
+       << " anoPresenceInd:" << control.m_anoPresenceInd
+       << " chCntrFreqSeg1PresenceInd:" << control.m_chCntrFreqSeg1PresenceInd
+       << " primChPresenceInd:" << control.m_primChPresenceInd
+       << " rsnInfoPresenceInd:" << control.m_rsnInfoPresenceInd
+       << " lenPresenceInd:" << control.m_lenPresenceInd
+       << " mdPresenceInd:" << control.m_mdPresenceInd;
+    return os;
+}
+
+void
+FilsDiscHeader::FilsDiscFrameControl::Serialize(Buffer::Iterator& start) const
+{
+    uint16_t val = m_ssidLen | ((m_capPresenceInd ? 1 : 0) << 5) | (m_shortSsidInd << 6) |
+                   ((m_apCsnPresenceInd ? 1 : 0) << 7) | ((m_anoPresenceInd ? 1 : 0) << 8) |
+                   ((m_chCntrFreqSeg1PresenceInd ? 1 : 0) << 9) |
+                   ((m_primChPresenceInd ? 1 : 0) << 10) | (m_rsnInfoPresenceInd << 11) |
+                   ((m_lenPresenceInd ? 1 : 0) << 12) | (m_mdPresenceInd << 13);
+    start.WriteHtolsbU16(val);
+}
+
+uint32_t
+FilsDiscHeader::FilsDiscFrameControl::Deserialize(Buffer::Iterator start)
+{
+    auto val = start.ReadLsbtohU16();
+
+    m_ssidLen = val & 0x001f;
+    m_capPresenceInd = ((val >> 5) & 0x0001) == 1;
+    m_shortSsidInd = (val >> 6) & 0x0001;
+    m_apCsnPresenceInd = ((val >> 7) & 0x0001) == 1;
+    m_anoPresenceInd = ((val >> 8) & 0x0001) == 1;
+    m_chCntrFreqSeg1PresenceInd = ((val >> 9) & 0x0001) == 1;
+    m_primChPresenceInd = ((val >> 10) & 0x0001) == 1;
+    m_rsnInfoPresenceInd = (val >> 11) & 0x0001;
+    m_lenPresenceInd = ((val >> 12) & 0x0001) == 1;
+    m_mdPresenceInd = (val >> 13) & 0x0001;
+
+    return 2;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const FilsDiscHeader::FdCapability& capability)
+{
+    os << "ess:" << capability.m_ess << " privacy:" << capability.m_privacy
+       << " channelWidth:" << capability.m_chWidth << " maxNss:" << capability.m_maxNss
+       << " multiBssidInd:" << capability.m_multiBssidPresenceInd
+       << " phyIdx:" << capability.m_phyIdx << " minRate:" << capability.m_minRate;
+    return os;
+}
+
+void
+FilsDiscHeader::FdCapability::Serialize(Buffer::Iterator& start) const
+{
+    uint16_t val = m_ess | (m_privacy << 1) | (m_chWidth << 2) | (m_maxNss << 5) |
+                   (m_multiBssidPresenceInd << 9) | (m_phyIdx << 10) | (m_minRate << 13);
+    start.WriteHtolsbU16(val);
+}
+
+uint32_t
+FilsDiscHeader::FdCapability::Deserialize(Buffer::Iterator start)
+{
+    auto val = start.ReadLsbtohU16();
+
+    m_ess = val & 0x0001;
+    m_privacy = (val >> 1) & 0x0001;
+    m_chWidth = (val >> 2) & 0x0007;
+    m_maxNss = (val >> 5) & 0x0007;
+    m_multiBssidPresenceInd = (val >> 9) & 0x0001;
+    m_phyIdx = (val >> 10) & 0x0007;
+    m_minRate = (val >> 13) & 0x0007;
+
+    return 2;
+}
+
+void
+FilsDiscHeader::FdCapability::SetOpChannelWidth(uint16_t width)
+{
+    m_chWidth = (width == 20 || width == 22) ? 0
+                : (width == 40)              ? 1
+                : (width == 80)              ? 2
+                : (width == 160)             ? 3
+                                             : 4;
+}
+
+uint16_t
+FilsDiscHeader::FdCapability::GetOpChannelWidth() const
+{
+    switch (m_chWidth)
+    {
+    case 0:
+        return m_phyIdx == 0 ? 22 : 20; // PHY Index 0 indicates 802.11b
+    case 1:
+        return 40;
+    case 2:
+        return 80;
+    case 3:
+        return 160;
+    default:
+        NS_ABORT_MSG("Reserved value: " << +m_chWidth);
+    }
+    return 0;
+}
+
+void
+FilsDiscHeader::FdCapability::SetMaxNss(uint8_t maxNss)
+{
+    NS_ABORT_MSG_IF(maxNss < 1, "NSS is equal to 0");
+    maxNss--;
+    // 4 is the maximum value for the Maximum Number of Spatial Streams subfield
+    m_maxNss = std::min<uint8_t>(maxNss, 4);
+}
+
+uint8_t
+FilsDiscHeader::FdCapability::GetMaxNss() const
+{
+    return m_maxNss + 1;
+}
+
+void
+FilsDiscHeader::FdCapability::SetStandard(WifiStandard standard)
+{
+    switch (standard)
+    {
+    case WIFI_STANDARD_80211b:
+        m_phyIdx = 0;
+        break;
+    case WIFI_STANDARD_80211a:
+    case WIFI_STANDARD_80211g:
+        m_phyIdx = 1;
+        break;
+    case WIFI_STANDARD_80211n:
+        m_phyIdx = 2;
+        break;
+    case WIFI_STANDARD_80211ac:
+        m_phyIdx = 3;
+        break;
+    case WIFI_STANDARD_80211ax:
+        m_phyIdx = 4;
+        break;
+    case WIFI_STANDARD_80211be:
+        m_phyIdx = 5;
+        break;
+    default:
+        NS_ABORT_MSG("Unsupported standard: " << standard);
+    }
+}
+
+WifiStandard
+FilsDiscHeader::FdCapability::GetStandard(WifiPhyBand band) const
+{
+    switch (m_phyIdx)
+    {
+    case 0:
+        return WIFI_STANDARD_80211b;
+    case 1:
+        NS_ABORT_MSG_IF(band != WIFI_PHY_BAND_2_4GHZ && band != WIFI_PHY_BAND_5GHZ,
+                        "Invalid PHY band (" << band << ") with PHY index of 1");
+        return band == WIFI_PHY_BAND_5GHZ ? WIFI_STANDARD_80211a : WIFI_STANDARD_80211g;
+    case 2:
+        return WIFI_STANDARD_80211n;
+    case 3:
+        return WIFI_STANDARD_80211ac;
+    case 4:
+        return WIFI_STANDARD_80211ax;
+    case 5:
+        return WIFI_STANDARD_80211be;
+    default:
+        NS_ABORT_MSG("Invalid PHY index: " << m_phyIdx);
+    }
+
+    return WIFI_STANDARD_UNSPECIFIED;
+}
+
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/mgt-action-headers.h ns-3.42/src/wifi/model/mgt-action-headers.h
--- ns-3.41/src/wifi/model/mgt-action-headers.h	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/mgt-action-headers.h	2024-05-29 15:29:47.204074000 -0700
@@ -22,7 +22,11 @@
 #ifndef MGT_ACTION_HEADERS_H
 #define MGT_ACTION_HEADERS_H
 
+#include "reduced-neighbor-report.h"
 #include "status-code.h"
+#include "tim.h"
+#include "wifi-opt-field.h"
+#include "wifi-standards.h"
 
 #include "ns3/header.h"
 
@@ -99,6 +103,7 @@
     {
         QAB_REQUEST = 16,
         QAB_RESPONSE = 17,
+        FILS_DISCOVERY = 34
     };
 
     /// RadioMeasurementActionValue enumeration
@@ -666,6 +671,175 @@
     std::optional<EmlsrParamUpdate> m_emlsrParamUpdate{}; //!< EMLSR Parameter Update field
 };
 
+/**
+ * \ingroup wifi
+ * Implement the FILS (Fast Initial Link Setup) action frame.
+ * See sec. 9.6.7.36 of IEEE 802.11-2020 and IEEE 802.11ax-2021.
+ */
+class FilsDiscHeader : public Header
+{
+  public:
+    FilsDiscHeader();
+
+    /// \return the object TypeId
+    static TypeId GetTypeId();
+    TypeId GetInstanceTypeId() const override;
+    void Print(std::ostream& os) const override;
+    uint32_t GetSerializedSize() const override;
+    void Serialize(Buffer::Iterator start) const override;
+    uint32_t Deserialize(Buffer::Iterator start) override;
+
+    /**
+     * Set the SSID field.
+     *
+     * \param ssid the SSID
+     */
+    void SetSsid(const std::string& ssid);
+
+    /// \return the SSID
+    const std::string& GetSsid() const;
+
+    /// \return size of FILS Discovery Information field in octets
+    uint32_t GetInformationFieldSize() const;
+
+    /// \return size of non-optional subfields in octets
+    uint32_t GetSizeNonOptSubfields() const;
+
+    /// \brief sets value of Length subfield
+    void SetLengthSubfield();
+
+    /// FILS Discovery Frame Control subfield of FILS Discovery Information field
+    struct FilsDiscFrameControl // 2 octets
+    {
+        uint8_t m_ssidLen : 5 {0};               ///< SSID Length
+        bool m_capPresenceInd{false};            ///< Capability Presence Indicator
+        uint8_t m_shortSsidInd : 1 {0};          ///< Short SSID Indicator (not supported)
+        bool m_apCsnPresenceInd{false};          ///< AP-CSN Presence Indicator
+        bool m_anoPresenceInd{false};            ///< ANO Presence Indicator
+        bool m_chCntrFreqSeg1PresenceInd{false}; ///< Channel Center Frequency Segment 1
+                                                 ///< Presence Indicator
+        bool m_primChPresenceInd{false};         ///< Primary Channel Presence Indicator
+        uint8_t m_rsnInfoPresenceInd : 1 {0};    ///< RSN info Presence Indicator (not supported)
+        bool m_lenPresenceInd{false};            ///< Length Presence Indicator
+        uint8_t m_mdPresenceInd : 1 {0};         ///< MD Presence Indicator (not supported)
+        uint8_t m_reserved : 2 {0};              ///< Reserved Bits
+
+        /**
+         * \brief serialize content to a given buffer
+         * \param start given input buffer iterator
+         */
+        void Serialize(Buffer::Iterator& start) const;
+
+        /**
+         * \brief read content from a given buffer
+         * \param start input buffer iterator
+         * \return number of read octets
+         */
+        uint32_t Deserialize(Buffer::Iterator start);
+    };
+
+    /// FD Capability subfield of FILS Discovery Information field
+    struct FdCapability // 2 octets
+    {
+        uint8_t m_ess : 1 {0};                   ///< ESS
+        uint8_t m_privacy : 1 {0};               ///< Privacy
+        uint8_t m_chWidth : 3 {0};               ///< BSS Operating Channel Width
+        uint8_t m_maxNss : 3 {0};                ///< Maximum Number of Spatial Streams
+        uint8_t m_reserved : 1 {0};              ///< Reserved Bit
+        uint8_t m_multiBssidPresenceInd : 1 {0}; ///< Multiple BSSIDs Presence Indicator
+        uint8_t m_phyIdx : 3 {0};                ///< PHY Index
+        uint8_t m_minRate : 3 {0};               ///< FILS Minimum Rate
+
+        /**
+         * \brief Set the BSS Operating Channel Width field based on the operating channel width
+         * \param width the operating channel width in MHz
+         */
+        void SetOpChannelWidth(uint16_t width);
+
+        /// \return the operating channel width encoded in the BSS Operating Channel Width field
+        uint16_t GetOpChannelWidth() const;
+
+        /**
+         * \brief Set the Maximum Number of Spatial Streams field
+         * \param maxNss the maximum number of supported spatial streams
+         */
+        void SetMaxNss(uint8_t maxNss);
+
+        /**
+         * Note that this function returns 5 if the maximum number of supported spatial streams
+         * is greater than 4.
+         *
+         * \return the maximum number of supported spatial streams
+         */
+        uint8_t GetMaxNss() const;
+
+        /**
+         * \brief Set the PHY Index field based on the given wifi standard
+         * \param standard the wifi standard
+         */
+        void SetStandard(WifiStandard standard);
+
+        /**
+         * \param band the PHY band in which the device is operating (needed to distinguish
+         *             between 802.11a and 802.11g)
+         * \return the wifi standard encoded in the PHY Index field
+         */
+        WifiStandard GetStandard(WifiPhyBand band) const;
+
+        /**
+         * \brief serialize content to a given buffer
+         * \param start given input buffer iterator
+         */
+        void Serialize(Buffer::Iterator& start) const;
+
+        /**
+         * \brief read content from a given buffer
+         * \param start input buffer iterator
+         * \return number of read octets
+         */
+        uint32_t Deserialize(Buffer::Iterator start);
+    };
+
+    // FILS Discovery Frame Information field
+    // TODO: add optional FD-RSN and Mobility domain subfields
+    FilsDiscFrameControl m_frameCtl;               ///< FILS Discovery Frame Control
+    uint64_t m_timeStamp{0};                       ///< Timestamp
+    uint16_t m_beaconInt{0};                       ///< Beacon Interval in TU (1024 us)
+    OptFieldWithPresenceInd<uint8_t> m_len;        ///< Length
+    OptFieldWithPresenceInd<FdCapability> m_fdCap; ///< FD Capability
+    std::optional<uint8_t> m_opClass;              ///< Operating Class
+    OptFieldWithPresenceInd<uint8_t> m_primaryCh;  ///< Primary Channel
+    OptFieldWithPresenceInd<uint8_t>
+        m_apConfigSeqNum;                            ///< AP Configuration Sequence Number (AP-CSN)
+    OptFieldWithPresenceInd<uint8_t> m_accessNetOpt; ///< Access Network Options
+    OptFieldWithPresenceInd<uint8_t> m_chCntrFreqSeg1; ///< Channel Center Frequency Segment 1
+
+    // (Optional) Information Elements
+    std::optional<ReducedNeighborReport> m_rnr; ///< Reduced Neighbor Report
+    std::optional<Tim> m_tim;                   ///< Traffic Indication Map element
+
+  private:
+    std::string m_ssid; ///< SSID
+};
+
+/**
+ * \brief Stream insertion operator.
+ *
+ * \param os the output stream
+ * \param control the Fils Discovery Frame Control field
+ * \returns a reference to the stream
+ */
+std::ostream& operator<<(std::ostream& os, const FilsDiscHeader::FilsDiscFrameControl& control);
+
+/**
+ * \brief Stream insertion operator.
+ *
+ * \param os the output stream
+ * \param capability the Fils Discovery Frame Capability field
+ * \returns a reference to the stream
+ */
+std::ostream& operator<<(std::ostream& os, const FilsDiscHeader::FdCapability& capability);
+
 } // namespace ns3
 
 #endif /* MGT_ACTION_HEADERS_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/mgt-headers.h ns-3.42/src/wifi/model/mgt-headers.h
--- ns-3.41/src/wifi/model/mgt-headers.h	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/mgt-headers.h	2024-05-29 15:29:47.204074000 -0700
@@ -35,6 +35,7 @@
 #include "ns3/eht-capabilities.h"
 #include "ns3/eht-operation.h"
 #include "ns3/erp-information.h"
+#include "ns3/he-6ghz-band-capabilities.h"
 #include "ns3/he-capabilities.h"
 #include "ns3/he-operation.h"
 #include "ns3/ht-capabilities.h"
@@ -96,6 +97,7 @@
                                      std::optional<ExtendedCapabilities>,
                                      std::optional<VhtCapabilities>,
                                      std::optional<HeCapabilities>,
+                                     std::optional<He6GhzBandCapabilities>,
                                      std::optional<EhtCapabilities>>;
 
 /// List of Information Elements included in Probe Response frames
@@ -114,6 +116,7 @@
                                       std::optional<HeCapabilities>,
                                       std::optional<HeOperation>,
                                       std::optional<MuEdcaParameterSet>,
+                                      std::optional<He6GhzBandCapabilities>,
                                       std::optional<MultiLinkElement>,
                                       std::optional<EhtCapabilities>,
                                       std::optional<EhtOperation>,
@@ -127,6 +130,7 @@
                                      std::optional<ExtendedCapabilities>,
                                      std::optional<VhtCapabilities>,
                                      std::optional<HeCapabilities>,
+                                     std::optional<He6GhzBandCapabilities>,
                                      std::optional<MultiLinkElement>,
                                      std::optional<EhtCapabilities>,
                                      std::vector<TidToLinkMapping>>;
@@ -143,6 +147,7 @@
                                       std::optional<HeCapabilities>,
                                       std::optional<HeOperation>,
                                       std::optional<MuEdcaParameterSet>,
+                                      std::optional<He6GhzBandCapabilities>,
                                       std::optional<MultiLinkElement>,
                                       std::optional<EhtCapabilities>,
                                       std::optional<EhtOperation>,
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/mpdu-aggregator.cc ns-3.42/src/wifi/model/mpdu-aggregator.cc
--- ns-3.41/src/wifi/model/mpdu-aggregator.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/mpdu-aggregator.cc	2024-05-29 15:29:47.204074000 -0700
@@ -150,6 +150,7 @@
     // Retrieve the Capabilities elements advertised by the recipient
     auto ehtCapabilities = stationManager->GetStationEhtCapabilities(recipient);
     auto heCapabilities = stationManager->GetStationHeCapabilities(recipient);
+    auto he6GhzCapabilities = stationManager->GetStationHe6GhzCapabilities(recipient);
     auto vhtCapabilities = stationManager->GetStationVhtCapabilities(recipient);
     auto htCapabilities = stationManager->GetStationHtCapabilities(recipient);
 
@@ -166,6 +167,10 @@
         NS_ABORT_MSG_IF(!heCapabilities, "HE Capabilities element not received");
 
         maxAmpduSize = std::min(maxAmpduSize, heCapabilities->GetMaxAmpduLength());
+        if (he6GhzCapabilities)
+        {
+            maxAmpduSize = std::min(maxAmpduSize, he6GhzCapabilities->GetMaxAmpduLength());
+        }
     }
     else if (modulation == WIFI_MOD_CLASS_VHT)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/msdu-aggregator.cc ns-3.42/src/wifi/model/msdu-aggregator.cc
--- ns-3.41/src/wifi/model/msdu-aggregator.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/msdu-aggregator.cc	2024-05-29 15:29:47.204074000 -0700
@@ -187,6 +187,7 @@
 
     // Retrieve the Capabilities elements advertised by the recipient
     auto ehtCapabilities = stationManager->GetStationEhtCapabilities(recipient);
+    auto he6GhzCapabilities = stationManager->GetStationHe6GhzCapabilities(recipient);
     auto vhtCapabilities = stationManager->GetStationVhtCapabilities(recipient);
     auto htCapabilities = stationManager->GetStationHtCapabilities(recipient);
 
@@ -199,12 +200,16 @@
     {
         maxMpduSize = ehtCapabilities->GetMaxMpduLength();
     }
+    else if (he6GhzCapabilities && m_mac->Is6GhzBand(m_linkId))
+    {
+        maxMpduSize = he6GhzCapabilities->GetMaxMpduLength();
+    }
     else if (vhtCapabilities && m_mac->GetWifiPhy(m_linkId)->GetPhyBand() != WIFI_PHY_BAND_2_4GHZ)
     {
         maxMpduSize = vhtCapabilities->GetMaxMpduLength();
     }
 
-    if (!htCapabilities)
+    if (!htCapabilities && !he6GhzCapabilities)
     {
         /* "A non-DMG STA shall not transmit an A-MSDU to a STA from which it has
          * not received a frame containing an HT Capabilities element" (Section
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/non-ht/dsss-error-rate-model.cc ns-3.42/src/wifi/model/non-ht/dsss-error-rate-model.cc
--- ns-3.41/src/wifi/model/non-ht/dsss-error-rate-model.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/non-ht/dsss-error-rate-model.cc	2024-05-29 15:29:47.204074000 -0700
@@ -44,8 +44,8 @@
 DsssErrorRateModel::DqpskFunction(double x)
 {
     NS_LOG_FUNCTION_NOARGS();
-    return ((std::sqrt(2.0) + 1.0) / std::sqrt(8.0 * M_PI * std::sqrt(2.0))) *
-           (1.0 / std::sqrt(x)) * std::exp(-(2.0 - std::sqrt(2.0)) * x);
+    return ((M_SQRT2 + 1.0) / std::sqrt(8.0 * M_PI * M_SQRT2)) * (1.0 / std::sqrt(x)) *
+           std::exp(-(2.0 - M_SQRT2) * x);
 }
 
 double
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/non-ht/dsss-phy.cc ns-3.42/src/wifi/model/non-ht/dsss-phy.cc
--- ns-3.41/src/wifi/model/non-ht/dsss-phy.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/non-ht/dsss-phy.cc	2024-05-29 15:29:47.204074000 -0700
@@ -32,6 +32,9 @@
 
 #include <array>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/non-ht/erp-ofdm-phy.cc ns-3.42/src/wifi/model/non-ht/erp-ofdm-phy.cc
--- ns-3.41/src/wifi/model/non-ht/erp-ofdm-phy.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/non-ht/erp-ofdm-phy.cc	2024-05-29 15:29:47.204074000 -0700
@@ -30,6 +30,9 @@
 
 #include <array>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/non-ht/ofdm-phy.cc ns-3.42/src/wifi/model/non-ht/ofdm-phy.cc
--- ns-3.41/src/wifi/model/non-ht/ofdm-phy.cc	2024-02-09 14:44:08.589794900 -0800
+++ ns-3.42/src/wifi/model/non-ht/ofdm-phy.cc	2024-05-29 15:29:47.204074000 -0700
@@ -32,6 +32,9 @@
 
 #include <array>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/phy-entity.cc ns-3.42/src/wifi/model/phy-entity.cc
--- ns-3.41/src/wifi/model/phy-entity.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/phy-entity.cc	2024-05-29 15:29:47.204074000 -0700
@@ -37,6 +37,9 @@
 
 #include <algorithm>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
@@ -158,7 +161,7 @@
 WifiPpduField
 PhyEntity::GetNextField(WifiPpduField currentField, WifiPreamble preamble) const
 {
-    auto ppduFormats = GetPpduFormats();
+    const auto& ppduFormats = GetPpduFormats();
     const auto itPpdu = ppduFormats.find(preamble);
     if (itPpdu != ppduFormats.end())
     {
@@ -337,7 +340,7 @@
                     NanoSeconds(0)); // this callback (equivalent to PHY-RXSTART primitive) is also
                                      // triggered for filtered PPDUs
             }
-            m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), status.reason);
+            m_wifiPhy->NotifyRxPpduDrop(ppdu, status.reason);
             m_wifiPhy->NotifyCcaBusy(ppdu, GetRemainingDurationAfterField(ppdu, field));
         // no break
         case IGNORE:
@@ -368,7 +371,7 @@
     NS_LOG_FUNCTION(this << field << *event);
     NS_ASSERT(field != WIFI_PPDU_FIELD_PREAMBLE &&
               field != WIFI_PPDU_FIELD_DATA); // handled apart for the time being
-    auto ppduFormats = GetPpduFormats();
+    const auto& ppduFormats = GetPpduFormats();
     auto itFormat = ppduFormats.find(event->GetPpdu()->GetPreamble());
     if (itFormat != ppduFormats.end())
     {
@@ -515,7 +518,7 @@
 PhyEntity::DropPreambleEvent(Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason, Time endRx)
 {
     NS_LOG_FUNCTION(this << ppdu << reason << endRx);
-    m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), reason);
+    m_wifiPhy->NotifyRxPpduDrop(ppdu, reason);
     auto it = m_wifiPhy->m_currentPreambleEvents.find({ppdu->GetUid(), ppdu->GetPreamble()});
     if (it != m_wifiPhy->m_currentPreambleEvents.end())
     {
@@ -738,6 +741,7 @@
         success = false;
     }
 
+    m_state->NotifyRxPpduOutcome(ppdu, rxSignalInfo, txVector, staId, statusPerMpduIt->second);
     DoEndReceivePayload(ppdu);
     m_wifiPhy->SwitchMaybeToCcaBusy(ppdu);
 
@@ -871,7 +875,11 @@
                                    RxPowerWattPerChannelBand& rxPower,
                                    bool isStartHePortionRxing /* = false */)
 {
-    return m_wifiPhy->m_interference->Add(ppdu, duration, rxPower, isStartHePortionRxing);
+    return m_wifiPhy->m_interference->Add(ppdu,
+                                          duration,
+                                          rxPower,
+                                          m_wifiPhy->GetCurrentFrequencyRange(),
+                                          isStartHePortionRxing);
 }
 
 void
@@ -887,7 +895,7 @@
         // interference
         event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPower);
         NS_LOG_DEBUG("Drop PPDU that arrived too late");
-        m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), PPDU_TOO_LATE);
+        m_wifiPhy->NotifyRxPpduDrop(ppdu, PPDU_TOO_LATE);
         return;
     }
 
@@ -938,8 +946,9 @@
 {
     NS_LOG_FUNCTION(this << *event);
     NS_LOG_DEBUG("Sync to signal (power=" << WToDbm(GetRxPowerWForPpdu(event)) << "dBm)");
-    m_wifiPhy->m_interference
-        ->NotifyRxStart(); // We need to notify it now so that it starts recording events
+    m_wifiPhy->m_interference->NotifyRxStart(
+        m_wifiPhy->GetCurrentFrequencyRange()); // We need to notify it now so that it starts
+                                                // recording events
     m_endPreambleDetectionEvents.push_back(
         Simulator::Schedule(m_wifiPhy->GetPreambleDetectionDuration(),
                             &PhyEntity::EndPreambleDetectionPeriod,
@@ -979,7 +988,8 @@
                      << maxEvent->GetPpdu()->GetUid()
                      << " during preamble detection: drop packet with UID "
                      << event->GetPpdu()->GetUid());
-        m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(event->GetPpdu()), BUSY_DECODING_PREAMBLE);
+        m_wifiPhy->NotifyRxPpduDrop(event->GetPpdu(), BUSY_DECODING_PREAMBLE);
+
         auto it = m_wifiPhy->m_currentPreambleEvents.find(
             {event->GetPpdu()->GetUid(), event->GetPpdu()->GetPreamble()});
         m_wifiPhy->m_currentPreambleEvents.erase(it);
@@ -988,7 +998,7 @@
         m_wifiPhy->m_interference->NotifyRxEnd(maxEvent->GetStartTime(),
                                                m_wifiPhy->GetCurrentFrequencyRange());
         // Make sure InterferenceHelper keeps recording events
-        m_wifiPhy->m_interference->NotifyRxStart();
+        m_wifiPhy->m_interference->NotifyRxStart(m_wifiPhy->GetCurrentFrequencyRange());
         return;
     }
 
@@ -1035,7 +1045,8 @@
                 {
                     reason = BUSY_DECODING_PREAMBLE;
                 }
-                m_wifiPhy->NotifyRxDrop(GetAddressedPsduInPpdu(it->second->GetPpdu()), reason);
+                m_wifiPhy->NotifyRxPpduDrop(it->second->GetPpdu(), reason);
+
                 it = m_wifiPhy->m_currentPreambleEvents.erase(it);
             }
             else
@@ -1045,7 +1056,7 @@
         }
 
         // Make sure InterferenceHelper keeps recording events
-        m_wifiPhy->m_interference->NotifyRxStart();
+        m_wifiPhy->m_interference->NotifyRxStart(m_wifiPhy->GetCurrentFrequencyRange());
 
         m_wifiPhy->NotifyRxBegin(GetAddressedPsduInPpdu(m_wifiPhy->m_currentEvent->GetPpdu()),
                                  m_wifiPhy->m_currentEvent->GetRxPowerWPerBand());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/qos-frame-exchange-manager.cc ns-3.42/src/wifi/model/qos-frame-exchange-manager.cc
--- ns-3.41/src/wifi/model/qos-frame-exchange-manager.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/qos-frame-exchange-manager.cc	2024-05-29 15:29:47.204074000 -0700
@@ -27,7 +27,7 @@
 #include "ns3/log.h"
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
@@ -149,7 +149,7 @@
 QosFrameExchangeManager::CancelPifsRecovery()
 {
     NS_LOG_FUNCTION(this);
-    NS_ASSERT(m_pifsRecoveryEvent.IsRunning());
+    NS_ASSERT(m_pifsRecoveryEvent.IsPending());
     NS_ASSERT(m_edca);
 
     NS_LOG_DEBUG("Cancel PIFS recovery being attempted by EDCAF " << m_edca);
@@ -162,7 +162,7 @@
 {
     NS_LOG_FUNCTION(this << edca << allowedWidth);
 
-    if (m_pifsRecoveryEvent.IsRunning())
+    if (m_pifsRecoveryEvent.IsPending())
     {
         // Another AC (having AIFS=1 or lower, if the user changed the default settings)
         // gained channel access while performing PIFS recovery. Abort PIFS recovery
@@ -186,7 +186,7 @@
 {
     NS_LOG_FUNCTION(this << edca << txopDuration);
 
-    if (m_pifsRecoveryEvent.IsRunning())
+    if (m_pifsRecoveryEvent.IsPending())
     {
         // Another AC (having AIFS=1 or lower, if the user changed the default settings)
         // gained channel access while performing PIFS recovery. Abort PIFS recovery
@@ -311,6 +311,8 @@
     {
         WifiTxParameters fragmentTxParams;
         fragmentTxParams.m_txVector = txParams.m_txVector;
+        fragmentTxParams.AddMpdu(item);
+        UpdateTxDuration(item->GetHeader().GetAddr1(), fragmentTxParams);
         txParams.m_protection = GetProtectionManager()->TryAddMpdu(item, fragmentTxParams);
         NS_ASSERT(txParams.m_protection);
     }
@@ -334,8 +336,13 @@
     NS_ASSERT(mpdu);
     NS_LOG_FUNCTION(this << *mpdu << &txParams << availableTime);
 
+    // tentatively add the given MPDU
+    auto prevTxDuration = txParams.m_txDuration;
+    txParams.AddMpdu(mpdu);
+    UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
+
     // check if adding the given MPDU requires a different protection method
-    Time protectionTime = Time::Min(); // uninitialized
+    std::optional<Time> protectionTime; // uninitialized
     if (txParams.m_protection)
     {
         protectionTime = txParams.m_protection->protectionTime;
@@ -355,11 +362,11 @@
         txParams.m_protection.swap(protection);
         protectionSwapped = true;
     }
-    NS_ASSERT(protectionTime != Time::Min());
-    NS_LOG_DEBUG("protection time=" << protectionTime);
+    NS_ASSERT(protectionTime.has_value());
+    NS_LOG_DEBUG("protection time=" << *protectionTime);
 
     // check if adding the given MPDU requires a different acknowledgment method
-    Time acknowledgmentTime = Time::Min(); // uninitialized
+    std::optional<Time> acknowledgmentTime; // uninitialized
     if (txParams.m_acknowledgment)
     {
         acknowledgmentTime = txParams.m_acknowledgment->acknowledgmentTime;
@@ -379,19 +386,21 @@
         txParams.m_acknowledgment.swap(acknowledgment);
         acknowledgmentSwapped = true;
     }
-    NS_ASSERT(acknowledgmentTime != Time::Min());
-    NS_LOG_DEBUG("acknowledgment time=" << acknowledgmentTime);
+    NS_ASSERT(acknowledgmentTime.has_value());
+    NS_LOG_DEBUG("acknowledgment time=" << *acknowledgmentTime);
 
     Time ppduDurationLimit = Time::Min();
     if (availableTime != Time::Min())
     {
-        ppduDurationLimit = availableTime - protectionTime - acknowledgmentTime;
+        ppduDurationLimit = availableTime - *protectionTime - *acknowledgmentTime;
     }
 
     if (!IsWithinLimitsIfAddMpdu(mpdu, txParams, ppduDurationLimit))
     {
-        // adding MPDU failed, restore protection and acknowledgment methods
-        // if they were swapped
+        // adding MPDU failed, undo the addition of the MPDU and restore protection and
+        // acknowledgment methods if they were swapped
+        txParams.UndoAddMpdu();
+        txParams.m_txDuration = prevTxDuration;
         if (protectionSwapped)
         {
             txParams.m_protection.swap(protection);
@@ -403,10 +412,6 @@
         return false;
     }
 
-    // the given MPDU can be added, hence update the txParams
-    txParams.AddMpdu(mpdu);
-    UpdateTxDuration(mpdu->GetHeader().GetAddr1(), txParams);
-
     return true;
 }
 
@@ -449,7 +454,8 @@
     // Get the maximum PPDU Duration based on the preamble type
     Time maxPpduDuration = GetPpduMaxTime(txParams.m_txVector.GetPreambleType());
 
-    Time txTime = GetTxDuration(ppduPayloadSize, receiver, txParams);
+    NS_ASSERT_MSG(txParams.m_txDuration, "TX duration not yet computed");
+    auto txTime = txParams.m_txDuration.value();
     NS_LOG_DEBUG("PPDU duration: " << txTime.As(Time::MS));
 
     if ((ppduDurationLimit.IsStrictlyPositive() && txTime > ppduDurationLimit) ||
@@ -483,7 +489,7 @@
     }
 
     NS_ASSERT(txParams.m_acknowledgment &&
-              txParams.m_acknowledgment->acknowledgmentTime != Time::Min());
+              txParams.m_acknowledgment->acknowledgmentTime.has_value());
 
     // under multiple protection settings, if the TXOP limit is not null, Duration/ID
     // is set to cover the remaining TXOP time (Sec. 9.2.5.2 of 802.11-2016).
@@ -491,7 +497,7 @@
     // of 802.11-2016)
     return std::max(m_edca->GetRemainingTxop(m_linkId) -
                         m_phy->CalculateTxDuration(size, txParams.m_txVector, m_phy->GetPhyBand()),
-                    txParams.m_acknowledgment->acknowledgmentTime);
+                    *txParams.m_acknowledgment->acknowledgmentTime);
 }
 
 Time
@@ -635,7 +641,7 @@
             // we can continue the TXOP if the carrier sense mechanism indicates that
             // the medium is idle in a PIFS
             NS_LOG_DEBUG("TX of a non-initial frame of a TXOP failed: perform PIFS recovery");
-            NS_ASSERT(!m_pifsRecoveryEvent.IsRunning());
+            NS_ASSERT(!m_pifsRecoveryEvent.IsPending());
             m_pifsRecoveryEvent =
                 Simulator::Schedule(m_phy->GetPifs(), &QosFrameExchangeManager::PifsRecovery, this);
         }
@@ -698,22 +704,31 @@
 QosFrameExchangeManager::SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector)
 {
     NS_LOG_FUNCTION(this << psdu << txVector);
+    if (auto txopHolder = FindTxopHolder(psdu->GetHeader(0), txVector))
+    {
+        m_txopHolder = *txopHolder;
+    }
+}
 
-    const WifiMacHeader& hdr = psdu->GetHeader(0);
+std::optional<Mac48Address>
+QosFrameExchangeManager::FindTxopHolder(const WifiMacHeader& hdr, const WifiTxVector& txVector)
+{
+    NS_LOG_FUNCTION(this << hdr << txVector);
 
     // A STA shall save the TXOP holder address for the BSS in which it is associated.
     // The TXOP holder address is the MAC address from the Address 2 field of the frame
     // that initiated a frame exchange sequence, except if this is a CTS frame, in which
     // case the TXOP holder address is the Address 1 field. (Sec. 10.23.2.4 of 802.11-2020)
-    if ((hdr.IsQosData() || hdr.IsMgt() || hdr.IsRts()) &&
+    if ((hdr.IsQosData() || hdr.IsMgt() || hdr.IsRts() || hdr.IsBlockAckReq()) &&
         (hdr.GetAddr1() == m_bssid || hdr.GetAddr2() == m_bssid))
     {
-        m_txopHolder = psdu->GetAddr2();
+        return hdr.GetAddr2();
     }
-    else if (hdr.IsCts() && hdr.GetAddr1() == m_bssid)
+    if (hdr.IsCts() && hdr.GetAddr1() == m_bssid)
     {
-        m_txopHolder = psdu->GetAddr1();
+        return hdr.GetAddr1();
     }
+    return std::nullopt;
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/qos-frame-exchange-manager.h ns-3.42/src/wifi/model/qos-frame-exchange-manager.h
--- ns-3.41/src/wifi/model/qos-frame-exchange-manager.h	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/qos-frame-exchange-manager.h	2024-05-29 15:29:47.204074000 -0700
@@ -171,12 +171,14 @@
     virtual bool SendCfEndIfNeeded();
 
     /**
-     * Set the TXOP holder, if needed, based on the received frame
+     * Determine the holder of the TXOP, if possible, based on the received frame
      *
-     * \param psdu the received PSDU
+     * \param hdr the MAC header of an MPDU included in the received PSDU
      * \param txVector TX vector of the received PSDU
+     * \return the holder of the TXOP, if one was found
      */
-    virtual void SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector);
+    virtual std::optional<Mac48Address> FindTxopHolder(const WifiMacHeader& hdr,
+                                                       const WifiTxVector& txVector);
 
     /**
      * Clear the TXOP holder if the NAV counted down to zero (includes the case of NAV reset).
@@ -190,6 +192,14 @@
 
   private:
     /**
+     * Set the TXOP holder, if needed, based on the received frame
+     *
+     * \param psdu the received PSDU
+     * \param txVector TX vector of the received PSDU
+     */
+    void SetTxopHolder(Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector);
+
+    /**
      * Cancel the PIFS recovery event and have the EDCAF attempting PIFS recovery
      * release the channel.
      */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/qos-txop.cc ns-3.42/src/wifi/model/qos-txop.cc
--- ns-3.41/src/wifi/model/qos-txop.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/qos-txop.cc	2024-05-29 15:29:47.204074000 -0700
@@ -35,6 +35,7 @@
 #include "wifi-psdu.h"
 #include "wifi-tx-parameters.h"
 
+#include "ns3/ht-configuration.h"
 #include "ns3/ht-frame-exchange-manager.h"
 #include "ns3/log.h"
 #include "ns3/pointer.h"
@@ -42,11 +43,7 @@
 #include "ns3/simulator.h"
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT                                                                      \
-    if (m_mac)                                                                                     \
-    {                                                                                              \
-        std::clog << "[mac=" << m_mac->GetAddress() << "] ";                                       \
-    }
+#define NS_LOG_APPEND_CONTEXT WIFI_TXOP_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
@@ -103,12 +100,18 @@
     return tid;
 }
 
-QosTxop::QosTxop(AcIndex ac)
-    : Txop(CreateObject<WifiMacQueue>(ac)),
-      m_ac(ac)
+QosTxop::QosTxop()
 {
     NS_LOG_FUNCTION(this);
     m_baManager = CreateObject<BlockAckManager>();
+}
+
+void
+QosTxop::CreateQueue(AcIndex aci)
+{
+    NS_LOG_FUNCTION(this << aci);
+    Txop::CreateQueue(aci);
+    m_ac = aci;
     m_baManager->SetQueue(m_queue);
     m_baManager->SetBlockDestinationCallback(
         Callback<void, Mac48Address, uint8_t>([this](Mac48Address recipient, uint8_t tid) {
@@ -334,10 +337,14 @@
 {
     // remove MSDUs with expired lifetime starting from the head of the queue
     m_queue->WipeAllExpiredMpdus();
-    bool queueIsNotEmpty = (bool)(m_queue->PeekFirstAvailable(linkId));
+    auto hasFramesToTransmit = static_cast<bool>(m_queue->PeekFirstAvailable(linkId));
 
-    NS_LOG_FUNCTION(this << queueIsNotEmpty);
-    return queueIsNotEmpty;
+    // Print the number of packets that are actually in the queue (which might not be
+    // eligible for transmission for some reason, e.g., TID not mapped to the link, etc.)
+    NS_LOG_DEBUG(m_ac << " on link " << +linkId << (hasFramesToTransmit ? " has" : " has not")
+                      << " frames to transmit with " << m_queue->GetNPackets()
+                      << " packets in the queue");
+    return hasFramesToTransmit;
 }
 
 uint16_t
@@ -387,7 +394,7 @@
         }
         WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE, WIFI_UNICAST, recipient, tid);
         if (auto mask = m_mac->GetMacQueueScheduler()->GetQueueLinkMask(m_ac, queueId, linkId);
-            !mask || mask->none())
+            mask && mask->none())
         {
             return m_queue->PeekByQueueId(queueId, mpdu);
         }
@@ -425,7 +432,7 @@
             // if the MPDU is not already in-flight on the link for which we are requesting an
             // MPDU and the number of links on which the MPDU is in-flight is less than the
             // maximum number, then we can transmit this MPDU
-            if (linkIds.count(linkId) == 0 && linkIds.size() < m_nMaxInflights)
+            if (!linkIds.contains(linkId) && (linkIds.size() < m_nMaxInflights))
             {
                 break;
             }
@@ -535,7 +542,7 @@
 
         // try A-MSDU aggregation if the MPDU does not contain an A-MSDU and does not already
         // have a sequence number assigned (may be a retransmission)
-        if (m_mac->GetHtSupported() && !recipient.IsBroadcast() &&
+        if (m_mac->GetHtConfiguration() && !recipient.IsBroadcast() &&
             !peekedItem->GetHeader().IsQosAmsdu() && !peekedItem->HasSeqNoAssigned() &&
             !peekedItem->IsFragment())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/qos-txop.h ns-3.42/src/wifi/model/qos-txop.h
--- ns-3.41/src/wifi/model/qos-txop.h	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/qos-txop.h	2024-05-29 15:29:47.204074000 -0700
@@ -79,13 +79,7 @@
      */
     static TypeId GetTypeId();
 
-    /**
-     * Constructor
-     *
-     * \param ac the Access Category
-     */
-    QosTxop(AcIndex ac = AC_UNDEF);
-
+    QosTxop();
     ~QosTxop() override;
 
     bool IsQosTxop() const override;
@@ -439,6 +433,7 @@
     };
 
     void DoDispose() override;
+    void CreateQueue(AcIndex aci) override;
 
     /**
      * Get a reference to the link associated with the given ID.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/rate-control/aparf-wifi-manager.cc ns-3.42/src/wifi/model/rate-control/aparf-wifi-manager.cc
--- ns-3.41/src/wifi/model/rate-control/aparf-wifi-manager.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/rate-control/aparf-wifi-manager.cc	2024-05-29 15:29:47.204074000 -0700
@@ -278,13 +278,10 @@
     NS_LOG_DEBUG("station=" << station << " data ok success=" << station->m_nSuccess << ", rate="
                             << +station->m_rateIndex << ", power=" << +station->m_powerLevel);
 
-    if ((station->m_aparfState == AparfWifiManager::High) &&
-        (station->m_nSuccess >= station->m_successThreshold))
-    {
-        station->m_aparfState = AparfWifiManager::Spread;
-    }
-    else if ((station->m_aparfState == AparfWifiManager::Low) &&
-             (station->m_nSuccess >= station->m_successThreshold))
+    if ((station->m_aparfState == AparfWifiManager::High ||
+         station->m_aparfState == AparfWifiManager::Low) &&
+        station->m_nSuccess >= station->m_successThreshold)
+
     {
         station->m_aparfState = AparfWifiManager::Spread;
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/rate-control/ideal-wifi-manager.cc ns-3.42/src/wifi/model/rate-control/ideal-wifi-manager.cc
--- ns-3.41/src/wifi/model/rate-control/ideal-wifi-manager.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/rate-control/ideal-wifi-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -19,7 +19,9 @@
 
 #include "ideal-wifi-manager.h"
 
+#include "ns3/ht-configuration.h"
 #include "ns3/log.h"
+#include "ns3/wifi-net-device.h"
 #include "ns3/wifi-phy.h"
 
 #include <algorithm>
@@ -130,7 +132,7 @@
         AddSnrThreshold(txVector, GetPhy()->CalculateSnr(txVector, m_ber));
     }
     // Add all MCSes
-    if (GetHtSupported())
+    if (GetPhy()->GetDevice()->GetHtConfiguration())
     {
         for (const auto& mode : GetPhy()->GetMcsList())
         {
@@ -360,7 +362,8 @@
     }
     else
     {
-        if (GetHtSupported() && GetHtSupported(st))
+        if (GetPhy()->GetDevice()->GetHtConfiguration() &&
+            (GetHtSupported(st) || GetStationHe6GhzCapabilities(st->m_state->m_address)))
         {
             for (uint8_t i = 0; i < GetNMcsSupported(station); i++)
             {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc ns-3.42/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc
--- ns-3.41/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/rate-control/minstrel-ht-wifi-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -35,11 +35,13 @@
 
 #include "minstrel-ht-wifi-manager.h"
 
+#include "ns3/ht-configuration.h"
 #include "ns3/log.h"
 #include "ns3/packet.h"
 #include "ns3/random-variable-stream.h"
 #include "ns3/simulator.h"
 #include "ns3/wifi-mac.h"
+#include "ns3/wifi-net-device.h"
 #include "ns3/wifi-phy.h"
 
 #include <iomanip>
@@ -196,32 +198,35 @@
     {
         m_numGroups = MAX_HT_SUPPORTED_STREAMS * MAX_HT_STREAM_GROUPS;
         m_numRates = MAX_HT_GROUP_RATES;
-        if (GetVhtSupported())
-        {
-            m_numGroups += MAX_VHT_SUPPORTED_STREAMS * MAX_VHT_STREAM_GROUPS;
-            m_numRates = MAX_VHT_GROUP_RATES;
-        }
-        if (GetHeSupported())
-        {
-            m_numGroups += MAX_HE_SUPPORTED_STREAMS * MAX_HE_STREAM_GROUPS;
-            m_numRates = MAX_HE_GROUP_RATES;
-        }
+    }
+    if (GetVhtSupported())
+    {
+        m_numGroups += MAX_VHT_SUPPORTED_STREAMS * MAX_VHT_STREAM_GROUPS;
+        m_numRates = MAX_VHT_GROUP_RATES;
+    }
+    if (GetHeSupported())
+    {
+        m_numGroups += MAX_HE_SUPPORTED_STREAMS * MAX_HE_STREAM_GROUPS;
+        m_numRates = MAX_HE_GROUP_RATES;
+    }
 
-        /**
-         *  Initialize the groups array.
-         *  The HT groups come first, then the VHT ones, and finally the HE ones.
-         *  Minstrel maintains different types of indexes:
-         *  - A global continuous index, which identifies all rates within all groups, in [0,
-         * m_numGroups * m_numRates]
-         *  - A groupId, which indexes a group in the array, in [0, m_numGroups]
-         *  - A rateId, which identifies a rate within a group, in [0, m_numRates]
-         *  - A deviceIndex, which indexes a MCS in the PHY MCS array.
-         *  - A mcsIndex, which indexes a MCS in the wifi-remote-station-manager supported MCSs
-         * array.
-         */
-        NS_LOG_DEBUG("Initialize MCS Groups:");
-        m_minstrelGroups = MinstrelMcsGroups(m_numGroups);
+    /**
+     *  Initialize the groups array.
+     *  The HT groups come first, then the VHT ones, and finally the HE ones.
+     *  Minstrel maintains different types of indexes:
+     *  - A global continuous index, which identifies all rates within all groups, in [0,
+     * m_numGroups * m_numRates]
+     *  - A groupId, which indexes a group in the array, in [0, m_numGroups]
+     *  - A rateId, which identifies a rate within a group, in [0, m_numRates]
+     *  - A deviceIndex, which indexes a MCS in the PHY MCS array.
+     *  - A mcsIndex, which indexes a MCS in the wifi-remote-station-manager supported MCSs
+     * array.
+     */
+    NS_LOG_DEBUG("Initialize MCS Groups:");
+    m_minstrelGroups = MinstrelMcsGroups(m_numGroups);
 
+    if (GetHtSupported())
+    {
         // Initialize all HT groups
         for (uint16_t chWidth = 20; chWidth <= MAX_HT_WIDTH; chWidth *= 2)
         {
@@ -277,133 +282,129 @@
                 gi /= 2;
             }
         }
+    }
 
-        if (GetVhtSupported())
+    if (GetVhtSupported())
+    {
+        // Initialize all VHT groups
+        for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
         {
-            // Initialize all VHT groups
-            for (uint16_t chWidth = 20; chWidth <= MAX_VHT_WIDTH; chWidth *= 2)
+            for (int gi = 800; gi >= 400;)
             {
-                for (int gi = 800; gi >= 400;)
+                for (uint8_t streams = 1; streams <= MAX_VHT_SUPPORTED_STREAMS; streams++)
                 {
-                    for (uint8_t streams = 1; streams <= MAX_VHT_SUPPORTED_STREAMS; streams++)
+                    uint8_t groupId = GetVhtGroupId(streams, gi, chWidth);
+
+                    m_minstrelGroups[groupId].streams = streams;
+                    m_minstrelGroups[groupId].gi = gi;
+                    m_minstrelGroups[groupId].chWidth = chWidth;
+                    m_minstrelGroups[groupId].type = WIFI_MINSTREL_GROUP_VHT;
+                    m_minstrelGroups[groupId].isSupported = false;
+
+                    // Check capabilities of the device
+                    if (!(!GetShortGuardIntervalSupported() &&
+                          (gi == 400)) /// Is SGI supported by the transmitter?
+                        && (GetPhy()->GetChannelWidth() >=
+                            chWidth) /// Is channel width supported by the transmitter?
+                        && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
+                            streams)) /// Are streams supported by the transmitter?
                     {
-                        uint8_t groupId = GetVhtGroupId(streams, gi, chWidth);
+                        m_minstrelGroups[groupId].isSupported = true;
 
-                        m_minstrelGroups[groupId].streams = streams;
-                        m_minstrelGroups[groupId].gi = gi;
-                        m_minstrelGroups[groupId].chWidth = chWidth;
-                        m_minstrelGroups[groupId].type = WIFI_MINSTREL_GROUP_VHT;
-                        m_minstrelGroups[groupId].isSupported = false;
-
-                        // Check capabilities of the device
-                        if (!(!GetShortGuardIntervalSupported() &&
-                              (gi == 400)) /// Is SGI supported by the transmitter?
-                            && (GetPhy()->GetChannelWidth() >=
-                                chWidth) /// Is channel width supported by the transmitter?
-                            && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
-                                streams)) /// Are streams supported by the transmitter?
+                        // Calculate TX time for all rates of the group
+                        WifiModeList vhtMcsList = GetVhtDeviceMcsList();
+                        for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
                         {
-                            m_minstrelGroups[groupId].isSupported = true;
-
-                            // Calculate TX time for all rates of the group
-                            WifiModeList vhtMcsList = GetVhtDeviceMcsList();
-                            for (uint8_t i = 0; i < MAX_VHT_GROUP_RATES; i++)
+                            WifiMode mode = vhtMcsList[i];
+                            // Check for invalid VHT MCSs and do not add time to array.
+                            if (IsValidMcs(GetPhy(), streams, chWidth, mode))
                             {
-                                WifiMode mode = vhtMcsList[i];
-                                // Check for invalid VHT MCSs and do not add time to array.
-                                if (IsValidMcs(GetPhy(), streams, chWidth, mode))
-                                {
-                                    AddFirstMpduTxTime(
-                                        groupId,
-                                        mode,
-                                        CalculateMpduTxDuration(GetPhy(),
-                                                                streams,
-                                                                gi,
-                                                                chWidth,
-                                                                mode,
-                                                                FIRST_MPDU_IN_AGGREGATE));
-                                    AddMpduTxTime(
-                                        groupId,
-                                        mode,
-                                        CalculateMpduTxDuration(GetPhy(),
-                                                                streams,
-                                                                gi,
-                                                                chWidth,
-                                                                mode,
-                                                                MIDDLE_MPDU_IN_AGGREGATE));
-                                }
+                                AddFirstMpduTxTime(
+                                    groupId,
+                                    mode,
+                                    CalculateMpduTxDuration(GetPhy(),
+                                                            streams,
+                                                            gi,
+                                                            chWidth,
+                                                            mode,
+                                                            FIRST_MPDU_IN_AGGREGATE));
+                                AddMpduTxTime(groupId,
+                                              mode,
+                                              CalculateMpduTxDuration(GetPhy(),
+                                                                      streams,
+                                                                      gi,
+                                                                      chWidth,
+                                                                      mode,
+                                                                      MIDDLE_MPDU_IN_AGGREGATE));
                             }
-                            NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams
-                                                              << "," << gi << "," << chWidth
-                                                              << ")");
                         }
+                        NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams << ","
+                                                          << gi << "," << chWidth << ")");
                     }
-                    gi /= 2;
                 }
+                gi /= 2;
             }
         }
+    }
 
-        if (GetHeSupported())
+    if (GetHeSupported())
+    {
+        // Initialize all HE groups
+        for (uint16_t chWidth = 20; chWidth <= MAX_HE_WIDTH; chWidth *= 2)
         {
-            // Initialize all HE groups
-            for (uint16_t chWidth = 20; chWidth <= MAX_HE_WIDTH; chWidth *= 2)
+            for (int gi = 3200; gi >= 800;)
             {
-                for (int gi = 3200; gi >= 800;)
+                for (uint8_t streams = 1; streams <= MAX_HE_SUPPORTED_STREAMS; streams++)
                 {
-                    for (uint8_t streams = 1; streams <= MAX_HE_SUPPORTED_STREAMS; streams++)
+                    uint8_t groupId = GetHeGroupId(streams, gi, chWidth);
+
+                    m_minstrelGroups[groupId].streams = streams;
+                    m_minstrelGroups[groupId].gi = gi;
+                    m_minstrelGroups[groupId].chWidth = chWidth;
+                    m_minstrelGroups[groupId].type = WIFI_MINSTREL_GROUP_HE;
+                    m_minstrelGroups[groupId].isSupported = false;
+
+                    // Check capabilities of the device
+                    if ((GetGuardInterval() <= gi) /// Is GI supported by the transmitter?
+                        && (GetPhy()->GetChannelWidth() >=
+                            chWidth) /// Is channel width supported by the transmitter?
+                        && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
+                            streams)) /// Are streams supported by the transmitter?
                     {
-                        uint8_t groupId = GetHeGroupId(streams, gi, chWidth);
+                        m_minstrelGroups[groupId].isSupported = true;
 
-                        m_minstrelGroups[groupId].streams = streams;
-                        m_minstrelGroups[groupId].gi = gi;
-                        m_minstrelGroups[groupId].chWidth = chWidth;
-                        m_minstrelGroups[groupId].type = WIFI_MINSTREL_GROUP_HE;
-                        m_minstrelGroups[groupId].isSupported = false;
-
-                        // Check capabilities of the device
-                        if ((GetGuardInterval() <= gi) /// Is GI supported by the transmitter?
-                            && (GetPhy()->GetChannelWidth() >=
-                                chWidth) /// Is channel width supported by the transmitter?
-                            && (GetPhy()->GetMaxSupportedTxSpatialStreams() >=
-                                streams)) /// Are streams supported by the transmitter?
+                        // Calculate tx time for all rates of the group
+                        WifiModeList heMcsList = GetHeDeviceMcsList();
+                        for (uint8_t i = 0; i < MAX_HE_GROUP_RATES; i++)
                         {
-                            m_minstrelGroups[groupId].isSupported = true;
-
-                            // Calculate tx time for all rates of the group
-                            WifiModeList heMcsList = GetHeDeviceMcsList();
-                            for (uint8_t i = 0; i < MAX_HE_GROUP_RATES; i++)
+                            WifiMode mode = heMcsList.at(i);
+                            // Check for invalid HE MCSs and do not add time to array.
+                            if (IsValidMcs(GetPhy(), streams, chWidth, mode))
                             {
-                                WifiMode mode = heMcsList.at(i);
-                                // Check for invalid HE MCSs and do not add time to array.
-                                if (IsValidMcs(GetPhy(), streams, chWidth, mode))
-                                {
-                                    AddFirstMpduTxTime(
-                                        groupId,
-                                        mode,
-                                        CalculateMpduTxDuration(GetPhy(),
-                                                                streams,
-                                                                gi,
-                                                                chWidth,
-                                                                mode,
-                                                                FIRST_MPDU_IN_AGGREGATE));
-                                    AddMpduTxTime(
-                                        groupId,
-                                        mode,
-                                        CalculateMpduTxDuration(GetPhy(),
-                                                                streams,
-                                                                gi,
-                                                                chWidth,
-                                                                mode,
-                                                                MIDDLE_MPDU_IN_AGGREGATE));
-                                }
+                                AddFirstMpduTxTime(
+                                    groupId,
+                                    mode,
+                                    CalculateMpduTxDuration(GetPhy(),
+                                                            streams,
+                                                            gi,
+                                                            chWidth,
+                                                            mode,
+                                                            FIRST_MPDU_IN_AGGREGATE));
+                                AddMpduTxTime(groupId,
+                                              mode,
+                                              CalculateMpduTxDuration(GetPhy(),
+                                                                      streams,
+                                                                      gi,
+                                                                      chWidth,
+                                                                      mode,
+                                                                      MIDDLE_MPDU_IN_AGGREGATE));
                             }
-                            NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams
-                                                              << "," << gi << "," << chWidth
-                                                              << ")");
                         }
+                        NS_LOG_DEBUG("Initialized group " << +groupId << ": (" << +streams << ","
+                                                          << gi << "," << chWidth << ")");
                     }
-                    gi /= 2;
                 }
+                gi /= 2;
             }
         }
     }
@@ -513,7 +514,7 @@
 
     // Use the variable in the station to indicate whether the device supports HT.
     // When correct information available it will be checked.
-    station->m_isHt = GetHtSupported();
+    station->m_isHt = static_cast<bool>(GetPhy()->GetDevice()->GetHtConfiguration());
 
     return station;
 }
@@ -533,7 +534,7 @@
          *  the station will not support HT either.
          *  We save from using another check and variable.
          */
-        if (!GetHtSupported(station))
+        if (!GetHtSupported(station) && !GetStationHe6GhzCapabilities(station->m_state->m_address))
         {
             NS_LOG_INFO("non-HT station " << station);
             station->m_isHt = false;
@@ -975,7 +976,7 @@
         return txRate;
     }
 
-    NS_ASSERT(GetHtSupported());
+    NS_ASSERT(GetPhy()->GetDevice()->GetHtConfiguration() != nullptr);
     NS_ASSERT(group.chWidth % 20 == 0);
     // try halving the channel width and check if the group with the same number of
     // streams and same GI is supported, until either a supported group is found or
@@ -1041,55 +1042,52 @@
         }
         return vector;
     }
-    else
-    {
-        station->m_txrate = UpdateRateAfterAllowedWidth(station->m_txrate, allowedWidth);
-        NS_LOG_DEBUG("DoGetDataMode m_txrate= " << station->m_txrate);
 
-        uint8_t rateId = GetRateId(station->m_txrate);
-        uint8_t groupId = GetGroupId(station->m_txrate);
-        uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
+    station->m_txrate = UpdateRateAfterAllowedWidth(station->m_txrate, allowedWidth);
+    NS_LOG_DEBUG("DoGetDataMode m_txrate= " << station->m_txrate);
 
-        NS_LOG_DEBUG("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId
-                                              << " mode= " << GetMcsSupported(station, mcsIndex));
+    uint8_t rateId = GetRateId(station->m_txrate);
+    uint8_t groupId = GetGroupId(station->m_txrate);
+    uint8_t mcsIndex = station->m_groupsTable[groupId].m_ratesTable[rateId].mcsIndex;
 
-        McsGroup group = m_minstrelGroups[groupId];
+    NS_LOG_DEBUG("DoGetDataMode rateId= " << +rateId << " groupId= " << +groupId
+                                          << " mode= " << GetMcsSupported(station, mcsIndex));
 
-        // Check consistency of rate selected.
-        if (((group.type == WIFI_MINSTREL_GROUP_HE) && (group.gi < GetGuardInterval(station))) ||
-            (((group.type == WIFI_MINSTREL_GROUP_HT) || (group.type == WIFI_MINSTREL_GROUP_VHT)) &&
-             (group.gi == 400) && !GetShortGuardIntervalSupported(station)) ||
-            (group.chWidth > GetChannelWidth(station)) ||
-            (group.streams > GetNumberOfSupportedStreams(station)))
-        {
-            NS_FATAL_ERROR("Inconsistent group selected. Group: ("
-                           << +group.streams << "," << group.gi << "," << group.chWidth << ")"
-                           << " Station capabilities: (" << GetNumberOfSupportedStreams(station)
-                           << ","
-                           << ((group.type == WIFI_MINSTREL_GROUP_HE)
-                                   ? GetGuardInterval(station)
-                                   : (GetShortGuardIntervalSupported(station) ? 400 : 800))
-                           << "," << GetChannelWidth(station) << ")");
-        }
-        WifiMode mode = GetMcsSupported(station, mcsIndex);
-        WifiTxVector txVector{
-            mode,
-            GetDefaultTxPowerLevel(),
-            GetPreambleForTransmission(mode.GetModulationClass(), GetShortPreambleEnabled()),
-            group.gi,
-            GetNumberOfAntennas(),
-            group.streams,
-            GetNess(station),
-            GetPhy()->GetTxBandwidth(mode, group.chWidth),
-            GetAggregation(station) && !station->m_isSampling};
-        uint64_t dataRate = mode.GetDataRate(txVector);
-        if (m_currentRate != dataRate && !station->m_isSampling)
-        {
-            NS_LOG_DEBUG("New datarate: " << dataRate);
-            m_currentRate = dataRate;
-        }
-        return txVector;
+    McsGroup group = m_minstrelGroups[groupId];
+
+    // Check consistency of rate selected.
+    if (((group.type == WIFI_MINSTREL_GROUP_HE) && (group.gi < GetGuardInterval(station))) ||
+        (((group.type == WIFI_MINSTREL_GROUP_HT) || (group.type == WIFI_MINSTREL_GROUP_VHT)) &&
+         (group.gi == 400) && !GetShortGuardIntervalSupported(station)) ||
+        (group.chWidth > GetChannelWidth(station)) ||
+        (group.streams > GetNumberOfSupportedStreams(station)))
+    {
+        NS_FATAL_ERROR("Inconsistent group selected. Group: ("
+                       << +group.streams << "," << group.gi << "," << group.chWidth << ")"
+                       << " Station capabilities: (" << GetNumberOfSupportedStreams(station) << ","
+                       << ((group.type == WIFI_MINSTREL_GROUP_HE)
+                               ? GetGuardInterval(station)
+                               : (GetShortGuardIntervalSupported(station) ? 400 : 800))
+                       << "," << GetChannelWidth(station) << ")");
+    }
+    WifiMode mode = GetMcsSupported(station, mcsIndex);
+    WifiTxVector txVector{
+        mode,
+        GetDefaultTxPowerLevel(),
+        GetPreambleForTransmission(mode.GetModulationClass(), GetShortPreambleEnabled()),
+        group.gi,
+        GetNumberOfAntennas(),
+        group.streams,
+        GetNess(station),
+        GetPhy()->GetTxBandwidth(mode, group.chWidth),
+        GetAggregation(station) && !station->m_isSampling};
+    uint64_t dataRate = mode.GetDataRate(txVector);
+    if (m_currentRate != dataRate && !station->m_isSampling)
+    {
+        NS_LOG_DEBUG("New datarate: " << dataRate);
+        m_currentRate = dataRate;
     }
+    return txVector;
 }
 
 WifiTxVector
@@ -2181,8 +2179,12 @@
     {
         widthIndex = 0;
     }
-    uint8_t groupId = (MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS); /// add all HT groups
-    if (GetVhtSupported()) /// This check is needed since we do not support VHT in 2.4 GHz band
+    uint8_t groupId = 0;
+    if (GetHtSupported()) // This check is needed since HT is not supported in 6 GHz band
+    {
+        groupId = MAX_HT_STREAM_GROUPS * MAX_HT_SUPPORTED_STREAMS;
+    }
+    if (GetVhtSupported()) // This check is needed since VHT is not supported in 2.4 and 6 GHz bands
     {
         groupId += MAX_VHT_STREAM_GROUPS * MAX_VHT_SUPPORTED_STREAMS; /// add all VHT groups
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/rate-control/minstrel-wifi-manager.cc ns-3.42/src/wifi/model/rate-control/minstrel-wifi-manager.cc
--- ns-3.41/src/wifi/model/rate-control/minstrel-wifi-manager.cc	2024-02-09 14:44:08.593795000 -0800
+++ ns-3.42/src/wifi/model/rate-control/minstrel-wifi-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -730,14 +730,10 @@
     uint8_t index_max_prob = 0;
     for (uint8_t i = 0; i < station->m_nModes; i++)
     {
-        if ((station->m_minstrelTable[i].ewmaProb >= 95 * 180) &&
-            (station->m_minstrelTable[i].throughput >=
-             station->m_minstrelTable[index_max_prob].throughput))
-        {
-            index_max_prob = i;
-            max_prob = station->m_minstrelTable[i].ewmaProb;
-        }
-        else if (station->m_minstrelTable[i].ewmaProb >= max_prob)
+        if ((station->m_minstrelTable[i].ewmaProb >= 95 * 180 &&
+             station->m_minstrelTable[i].throughput >=
+                 station->m_minstrelTable[index_max_prob].throughput) ||
+            (station->m_minstrelTable[i].ewmaProb >= max_prob))
         {
             index_max_prob = i;
             max_prob = station->m_minstrelTable[i].ewmaProb;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/reference/error-rate-tables.cc ns-3.42/src/wifi/model/reference/error-rate-tables.cc
--- ns-3.41/src/wifi/model/reference/error-rate-tables.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/reference/error-rate-tables.cc	2024-05-29 15:29:47.208073900 -0700
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2020 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Rohan Patidar <rpatidar@uw.edu>
+ *          Sébastien Deronne <sebastien.deronne@gmail.com>
+ *          Sian Jin <sianjin@uw.edu>
+ */
+
+// This file contains table data for the TableBasedErrorRateModel.  For more
+// information on the source of this data, see wifi module documentation.
+
+#include "error-rate-tables.h"
+
+namespace ns3
+{
+
+/// AWGN error table for BCC with reference size of 32 bytes
+const SnrPerTable AwgnErrorTableBcc32[ERROR_TABLE_BCC_MAX_NUM_MCS] = {
+    // MCS-0
+    {
+        {-3.50000, 1.00000},
+        {-3.00000, 0.99500},
+        {-2.50000, 0.94080},
+        {-2.00000, 0.82590},
+        {-1.50000, 0.58950},
+        {-1.00000, 0.30830},
+        {-0.50000, 0.12540},
+        {0.00000, 0.03440},
+        {0.50000, 0.00850},
+        {1.00000, 0.00150},
+        {1.50000, 0.00024},
+        {2.00000, 0.00009},
+        {2.50000, 0.00000},
+    },
+    // MCS-1
+    {
+        {-0.50000, 1.00000},
+        {0.00000, 0.99210},
+        {0.50000, 0.96710},
+        {1.00000, 0.83490},
+        {1.50000, 0.58740},
+        {2.00000, 0.31690},
+        {2.50000, 0.11820},
+        {3.00000, 0.03640},
+        {3.50000, 0.00850},
+        {4.00000, 0.00160},
+        {4.50000, 0.00026},
+        {5.00000, 0.00003},
+        {5.50000, 0.00000},
+    },
+    // MCS-2
+    {
+        {2.00000, 1.00000},
+        {2.50000, 0.99400},
+        {3.00000, 0.95880},
+        {3.50000, 0.85120},
+        {4.00000, 0.59900},
+        {4.50000, 0.31250},
+        {5.00000, 0.11710},
+        {5.50000, 0.03390},
+        {6.00000, 0.00780},
+        {6.50000, 0.00160},
+        {7.00000, 0.00028},
+        {7.50000, 0.00008},
+        {8.00000, 0.00000},
+    },
+    // MCS-3
+    {
+        {4.00000, 1.00000},
+        {4.50000, 0.99900},
+        {5.00000, 0.99800},
+        {5.50000, 0.96900},
+        {6.00000, 0.88430},
+        {6.50000, 0.74090},
+        {7.00000, 0.46510},
+        {7.50000, 0.25710},
+        {8.00000, 0.10800},
+        {8.50000, 0.03810},
+        {9.00000, 0.01190},
+        {9.50000, 0.00320},
+        {10.00000, 0.00076},
+        {10.50000, 0.00017},
+        {11.00000, 0.00003},
+        {11.50000, 0.00000},
+    },
+    // MCS-4
+    {
+        {8.00000, 1.00000},
+        {8.50000, 0.99900},
+        {9.00000, 0.94790},
+        {9.50000, 0.79890},
+        {10.00000, 0.59230},
+        {10.50000, 0.33700},
+        {11.00000, 0.15720},
+        {11.50000, 0.05420},
+        {12.00000, 0.01580},
+        {12.50000, 0.00400},
+        {13.00000, 0.00110},
+        {13.50000, 0.00027},
+        {14.00000, 0.00009},
+        {14.50000, 0.00000},
+    },
+    // MCS-5
+    {
+        {11.50000, 1.00000},
+        {12.00000, 0.99800},
+        {12.50000, 0.96530},
+        {13.00000, 0.89700},
+        {13.50000, 0.73010},
+        {14.00000, 0.52570},
+        {14.50000, 0.30580},
+        {15.00000, 0.15750},
+        {15.50000, 0.06460},
+        {16.00000, 0.02410},
+        {16.50000, 0.00790},
+        {17.00000, 0.00230},
+        {17.50000, 0.00069},
+        {18.00000, 0.00018},
+        {18.50000, 0.00004},
+        {19.00000, 0.00002},
+        {19.50000, 0.00000},
+    },
+    // MCS-6
+    {
+        {13.00000, 1.00000},
+        {13.50000, 0.99010},
+        {14.00000, 0.96250},
+        {14.50000, 0.83980},
+        {15.00000, 0.68660},
+        {15.50000, 0.46340},
+        {16.00000, 0.25200},
+        {16.50000, 0.11450},
+        {17.00000, 0.04610},
+        {17.50000, 0.01580},
+        {18.00000, 0.00490},
+        {18.50000, 0.00160},
+        {19.00000, 0.00039},
+        {19.50000, 0.00011},
+        {20.00000, 0.00002},
+        {20.50000, 0.00000},
+    },
+    // MCS-7
+    {
+        {14.00000, 1.00000},
+        {14.50000, 0.99700},
+        {15.00000, 0.98330},
+        {15.50000, 0.94260},
+        {16.00000, 0.84830},
+        {16.50000, 0.63470},
+        {17.00000, 0.43770},
+        {17.50000, 0.22260},
+        {18.00000, 0.11110},
+        {18.50000, 0.04400},
+        {19.00000, 0.01730},
+        {19.50000, 0.00530},
+        {20.00000, 0.00190},
+        {20.50000, 0.00052},
+        {21.00000, 0.00016},
+        {21.50000, 0.00004},
+        {22.00000, 0.00000},
+    },
+    // MCS-8
+    {
+        {17.50000, 1.00000},
+        {18.00000, 0.99600},
+        {18.50000, 0.98040},
+        {19.00000, 0.92860},
+        {19.50000, 0.82250},
+        {20.00000, 0.67500},
+        {20.50000, 0.44140},
+        {21.00000, 0.26660},
+        {21.50000, 0.13380},
+        {22.00000, 0.05950},
+        {22.50000, 0.02450},
+        {23.00000, 0.00910},
+        {23.50000, 0.00320},
+        {24.00000, 0.00098},
+        {24.50000, 0.00033},
+        {25.00000, 0.00014},
+        {25.50000, 0.00004},
+        {26.00000, 0.00000},
+    },
+    // MCS-9
+    {
+        {19.00000, 1.00000},
+        {19.50000, 0.99800},
+        {20.00000, 0.98910},
+        {20.50000, 0.95970},
+        {21.00000, 0.87500},
+        {21.50000, 0.73170},
+        {22.00000, 0.51540},
+        {22.50000, 0.30380},
+        {23.00000, 0.15240},
+        {23.50000, 0.06340},
+        {24.00000, 0.02470},
+        {24.50000, 0.00850},
+        {25.00000, 0.00290},
+        {25.50000, 0.00100},
+        {26.00000, 0.00017},
+        {26.50000, 0.00014},
+        {27.00000, 0.00002},
+        {27.50000, 0.00000},
+    },
+};
+
+/// AWGN error table for BCC with reference size of 1458 bytes
+const SnrPerTable AwgnErrorTableBcc1458[ERROR_TABLE_BCC_MAX_NUM_MCS] = {
+    // MCS-0
+    {
+        {-1.00000, 1.00000},
+        {-0.50000, 0.99400},
+        {0.00000, 0.81850},
+        {0.50000, 0.29080},
+        {1.00000, 0.06630},
+        {1.50000, 0.01120},
+        {2.00000, 0.00150},
+        {2.50000, 0.00015},
+        {3.00000, 0.00001},
+        {3.50000, 0.00000},
+    },
+    // MCS-1
+    {
+        {2.00000, 1.00000},
+        {2.50000, 0.99700},
+        {3.00000, 0.79440},
+        {3.50000, 0.30080},
+        {4.00000, 0.07280},
+        {4.50000, 0.01200},
+        {5.00000, 0.00150},
+        {5.50000, 0.00023},
+        {6.00000, 0.00000},
+    },
+    // MCS-2
+    {
+        {4.50000, 1.00000},
+        {5.00000, 0.99800},
+        {5.50000, 0.75780},
+        {6.00000, 0.30100},
+        {6.50000, 0.06760},
+        {7.00000, 0.01220},
+        {7.50000, 0.00230},
+        {8.00000, 0.00035},
+        {8.50000, 0.00004},
+        {9.00000, 0.00000},
+    },
+    // MCS-3
+    {
+        {7.50000, 1.00000},
+        {8.00000, 0.99400},
+        {8.50000, 0.84050},
+        {9.00000, 0.43410},
+        {9.50000, 0.14190},
+        {10.00000, 0.03740},
+        {10.50000, 0.00860},
+        {11.00000, 0.00190},
+        {11.50000, 0.00036},
+        {12.00000, 0.00005},
+        {12.50000, 0.00000},
+    },
+    // MCS-4
+    {
+        {11.00000, 1.00000},
+        {11.50000, 0.92690},
+        {12.00000, 0.51390},
+        {12.50000, 0.18260},
+        {13.00000, 0.04650},
+        {13.50000, 0.01100},
+        {14.00000, 0.00260},
+        {14.50000, 0.00041},
+        {15.00000, 0.00010},
+        {15.50000, 0.00000},
+    },
+    // MCS-5
+    {
+        {14.50000, 1.00000},
+        {15.00000, 0.99900},
+        {15.50000, 0.94790},
+        {16.00000, 0.66250},
+        {16.50000, 0.29780},
+        {17.00000, 0.10580},
+        {17.50000, 0.03340},
+        {18.00000, 0.00910},
+        {18.50000, 0.00230},
+        {19.00000, 0.00064},
+        {19.50000, 0.00017},
+        {20.00000, 0.00002},
+        {20.50000, 0.00000},
+    },
+    // MCS-6
+    {
+        {16.00000, 1.00000},
+        {16.50000, 0.99500},
+        {17.00000, 0.87960},
+        {17.50000, 0.51390},
+        {18.00000, 0.20910},
+        {18.50000, 0.06390},
+        {19.00000, 0.01860},
+        {19.50000, 0.00460},
+        {20.00000, 0.00130},
+        {20.50000, 0.00023},
+        {21.00000, 0.00002},
+        {21.50000, 0.00000},
+    },
+    // MCS-7
+    {
+        {17.50000, 1.00000},
+        {18.00000, 0.97850},
+        {18.50000, 0.73930},
+        {19.00000, 0.33750},
+        {19.50000, 0.12340},
+        {20.00000, 0.03550},
+        {20.50000, 0.01000},
+        {21.00000, 0.00270},
+        {21.50000, 0.00050},
+        {22.00000, 0.00009},
+        {22.50000, 0.00001},
+        {23.00000, 0.00000},
+    },
+    // MCS-8
+    {
+        {21.00000, 1.00000},
+        {21.50000, 0.99800},
+        {22.00000, 0.93990},
+        {22.50000, 0.67090},
+        {23.00000, 0.35250},
+        {23.50000, 0.13760},
+        {24.00000, 0.04750},
+        {24.50000, 0.01540},
+        {25.00000, 0.00520},
+        {25.50000, 0.00150},
+        {26.00000, 0.00036},
+        {26.50000, 0.00007},
+        {27.00000, 0.00000},
+    },
+    // MCS-9
+    {
+        {22.50000, 1.00000},
+        {23.00000, 0.99900},
+        {23.50000, 0.95060},
+        {24.00000, 0.68470},
+        {24.50000, 0.32610},
+        {25.00000, 0.12480},
+        {25.50000, 0.04090},
+        {26.00000, 0.01300},
+        {26.50000, 0.00360},
+        {27.00000, 0.00082},
+        {27.50000, 0.00010},
+        {28.00000, 0.00002},
+        {28.50000, 0.00001},
+        {29.00000, 0.00000},
+    },
+};
+
+/// AWGN error table for LDPC with reference size of 1458 bytes
+const SnrPerTable AwgnErrorTableLdpc1458[ERROR_TABLE_LDPC_MAX_NUM_MCS] = {
+    // MCS-0
+    {
+        {-1.50000, 1.00000},
+        {-1.25000, 0.97950},
+        {-1.00000, 0.60480},
+        {-0.75000, 0.17050},
+        {-0.50000, 0.03320},
+        {-0.25000, 0.00530},
+        {0.00000, 0.00085},
+        {0.25000, 0.00022},
+        {0.50000, 0.00004},
+        {0.75000, 0.00000},
+    },
+    // MCS-1
+    {
+        {1.50000, 1.00000},
+        {1.75000, 0.97470},
+        {2.00000, 0.62330},
+        {2.25000, 0.18590},
+        {2.50000, 0.03400},
+        {2.75000, 0.00550},
+        {3.00000, 0.00083},
+        {3.25000, 0.00015},
+        {3.50000, 0.00003},
+        {3.75000, 0.00000},
+    },
+    // MCS-2
+    {
+        {4.00000, 1.00000},
+        {4.25000, 0.98720},
+        {4.50000, 0.62560},
+        {4.75000, 0.15800},
+        {5.00000, 0.02090},
+        {5.25000, 0.00250},
+        {5.50000, 0.00034},
+        {5.75000, 0.00003},
+        {6.00000, 0.00000},
+    },
+    // MCS-3
+    {
+        {6.75000, 1.00000},
+        {7.00000, 0.99800},
+        {7.25000, 0.94340},
+        {7.50000, 0.57890},
+        {7.75000, 0.20640},
+        {8.00000, 0.04840},
+        {8.25000, 0.00930},
+        {8.50000, 0.00180},
+        {8.75000, 0.00040},
+        {9.00000, 0.00011},
+        {9.25000, 0.00002},
+        {9.50000, 0.00000},
+    },
+    // MCS-4
+    {{10.00000, 1.00000},
+     {10.25000, 0.99310},
+     {10.50000, 0.70890},
+     {10.75000, 0.24720},
+     {11.00000, 0.04700},
+     {11.25000, 0.00590},
+     {11.50000, 0.00091},
+     {11.75000, 0.00016},
+     {12.00000, 0.00003},
+     {12.25000, 0.00000}},
+    // MCS-5
+    {
+        {14.00000, 1.00000},
+        {14.25000, 0.99700},
+        {14.50000, 0.91830},
+        {14.75000, 0.53790},
+        {15.00000, 0.16610},
+        {15.25000, 0.03690},
+        {15.50000, 0.00650},
+        {15.75000, 0.00100},
+        {16.00000, 0.00031},
+        {16.25000, 0.00005},
+        {16.50000, 0.00000},
+    },
+    // MCS-6
+    {
+        {15.50000, 1.00000},
+        {15.75000, 0.98140},
+        {16.00000, 0.73930},
+        {16.25000, 0.33110},
+        {16.50000, 0.08150},
+        {16.75000, 0.01620},
+        {17.00000, 0.00270},
+        {17.25000, 0.00052},
+        {17.50000, 0.00005},
+        {17.75000, 0.00003},
+        {18.00000, 0.00000},
+    },
+    // MCS-7
+    {
+        {17.00000, 1.00000},
+        {17.25000, 0.97750},
+        {17.50000, 0.73980},
+        {17.75000, 0.33190},
+        {18.00000, 0.09640},
+        {18.25000, 0.02180},
+        {18.50000, 0.00470},
+        {18.75000, 0.00087},
+        {19.00000, 0.00018},
+        {19.25000, 0.00003},
+        {19.50000, 0.00000},
+    },
+    // MCS-8
+    {
+        {20.50000, 1.00000},
+        {20.75000, 0.99500},
+        {21.00000, 0.89700},
+        {21.25000, 0.56270},
+        {21.50000, 0.20920},
+        {21.75000, 0.05600},
+        {22.00000, 0.01170},
+        {22.25000, 0.00250},
+        {22.50000, 0.00038},
+        {22.75000, 0.00013},
+        {23.00000, 0.00004},
+        {23.25000, 0.00001},
+        {23.50000, 0.00000},
+    },
+    // MCS-9
+    {
+        {22.25000, 1.00000},
+        {22.50000, 0.99900},
+        {22.75000, 0.94080},
+        {23.00000, 0.63600},
+        {23.25000, 0.27190},
+        {23.50000, 0.08700},
+        {23.75000, 0.02210},
+        {24.00000, 0.00500},
+        {24.25000, 0.00110},
+        {24.50000, 0.00032},
+        {24.75000, 0.00004},
+        {25.00000, 0.00000},
+    },
+    // MCS-10
+    {
+        {25.75000, 1.00000},
+        {26.00000, 0.94970},
+        {26.25000, 0.68660},
+        {26.50000, 0.32940},
+        {26.75000, 0.11620},
+        {27.00000, 0.03440},
+        {27.25000, 0.00880},
+        {27.50000, 0.00210},
+        {27.75000, 0.00054},
+        {28.00000, 0.00009},
+        {28.25000, 0.00002},
+        {28.50000, 0.00000},
+    },
+    // MCS-11
+    {
+        {27.75000, 1.00000},
+        {28.00000, 0.94880},
+        {28.25000, 0.75260},
+        {28.50000, 0.40230},
+        {28.75000, 0.16210},
+        {29.00000, 0.05150},
+        {29.25000, 0.01310},
+        {29.50000, 0.00360},
+        {29.75000, 0.00100},
+        {30.00000, 0.00022},
+        {30.25000, 0.00006},
+        {30.50000, 0.00000},
+    },
+};
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/reference/error-rate-tables.h ns-3.42/src/wifi/model/reference/error-rate-tables.h
--- ns-3.41/src/wifi/model/reference/error-rate-tables.h	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/reference/error-rate-tables.h	2024-05-29 15:29:47.208073900 -0700
@@ -25,6 +25,10 @@
 #ifndef ERROR_RATE_TABLES_H
 #define ERROR_RATE_TABLES_H
 
+#include <cstdint>
+#include <utility>
+#include <vector>
+
 namespace ns3
 {
 
@@ -40,512 +44,13 @@
 typedef std::vector<std::pair<double /* SNR (dB) */, double /* PER */>> SnrPerTable;
 
 /// AWGN error table for BCC with reference size of 32 bytes
-static const SnrPerTable AwgnErrorTableBcc32[ERROR_TABLE_BCC_MAX_NUM_MCS] = {
-    // MCS-0
-    {
-        {-3.50000, 1.00000},
-        {-3.00000, 0.99500},
-        {-2.50000, 0.94080},
-        {-2.00000, 0.82590},
-        {-1.50000, 0.58950},
-        {-1.00000, 0.30830},
-        {-0.50000, 0.12540},
-        {0.00000, 0.03440},
-        {0.50000, 0.00850},
-        {1.00000, 0.00150},
-        {1.50000, 0.00024},
-        {2.00000, 0.00009},
-        {2.50000, 0.00000},
-    },
-    // MCS-1
-    {
-        {-0.50000, 1.00000},
-        {0.00000, 0.99210},
-        {0.50000, 0.96710},
-        {1.00000, 0.83490},
-        {1.50000, 0.58740},
-        {2.00000, 0.31690},
-        {2.50000, 0.11820},
-        {3.00000, 0.03640},
-        {3.50000, 0.00850},
-        {4.00000, 0.00160},
-        {4.50000, 0.00026},
-        {5.00000, 0.00003},
-        {5.50000, 0.00000},
-    },
-    // MCS-2
-    {
-        {2.00000, 1.00000},
-        {2.50000, 0.99400},
-        {3.00000, 0.95880},
-        {3.50000, 0.85120},
-        {4.00000, 0.59900},
-        {4.50000, 0.31250},
-        {5.00000, 0.11710},
-        {5.50000, 0.03390},
-        {6.00000, 0.00780},
-        {6.50000, 0.00160},
-        {7.00000, 0.00028},
-        {7.50000, 0.00008},
-        {8.00000, 0.00000},
-    },
-    // MCS-3
-    {
-        {4.00000, 1.00000},
-        {4.50000, 0.99900},
-        {5.00000, 0.99800},
-        {5.50000, 0.96900},
-        {6.00000, 0.88430},
-        {6.50000, 0.74090},
-        {7.00000, 0.46510},
-        {7.50000, 0.25710},
-        {8.00000, 0.10800},
-        {8.50000, 0.03810},
-        {9.00000, 0.01190},
-        {9.50000, 0.00320},
-        {10.00000, 0.00076},
-        {10.50000, 0.00017},
-        {11.00000, 0.00003},
-        {11.50000, 0.00000},
-    },
-    // MCS-4
-    {
-        {8.00000, 1.00000},
-        {8.50000, 0.99900},
-        {9.00000, 0.94790},
-        {9.50000, 0.79890},
-        {10.00000, 0.59230},
-        {10.50000, 0.33700},
-        {11.00000, 0.15720},
-        {11.50000, 0.05420},
-        {12.00000, 0.01580},
-        {12.50000, 0.00400},
-        {13.00000, 0.00110},
-        {13.50000, 0.00027},
-        {14.00000, 0.00009},
-        {14.50000, 0.00000},
-    },
-    // MCS-5
-    {
-        {11.50000, 1.00000},
-        {12.00000, 0.99800},
-        {12.50000, 0.96530},
-        {13.00000, 0.89700},
-        {13.50000, 0.73010},
-        {14.00000, 0.52570},
-        {14.50000, 0.30580},
-        {15.00000, 0.15750},
-        {15.50000, 0.06460},
-        {16.00000, 0.02410},
-        {16.50000, 0.00790},
-        {17.00000, 0.00230},
-        {17.50000, 0.00069},
-        {18.00000, 0.00018},
-        {18.50000, 0.00004},
-        {19.00000, 0.00002},
-        {19.50000, 0.00000},
-    },
-    // MCS-6
-    {
-        {13.00000, 1.00000},
-        {13.50000, 0.99010},
-        {14.00000, 0.96250},
-        {14.50000, 0.83980},
-        {15.00000, 0.68660},
-        {15.50000, 0.46340},
-        {16.00000, 0.25200},
-        {16.50000, 0.11450},
-        {17.00000, 0.04610},
-        {17.50000, 0.01580},
-        {18.00000, 0.00490},
-        {18.50000, 0.00160},
-        {19.00000, 0.00039},
-        {19.50000, 0.00011},
-        {20.00000, 0.00002},
-        {20.50000, 0.00000},
-    },
-    // MCS-7
-    {
-        {14.00000, 1.00000},
-        {14.50000, 0.99700},
-        {15.00000, 0.98330},
-        {15.50000, 0.94260},
-        {16.00000, 0.84830},
-        {16.50000, 0.63470},
-        {17.00000, 0.43770},
-        {17.50000, 0.22260},
-        {18.00000, 0.11110},
-        {18.50000, 0.04400},
-        {19.00000, 0.01730},
-        {19.50000, 0.00530},
-        {20.00000, 0.00190},
-        {20.50000, 0.00052},
-        {21.00000, 0.00016},
-        {21.50000, 0.00004},
-        {22.00000, 0.00000},
-    },
-    // MCS-8
-    {
-        {17.50000, 1.00000},
-        {18.00000, 0.99600},
-        {18.50000, 0.98040},
-        {19.00000, 0.92860},
-        {19.50000, 0.82250},
-        {20.00000, 0.67500},
-        {20.50000, 0.44140},
-        {21.00000, 0.26660},
-        {21.50000, 0.13380},
-        {22.00000, 0.05950},
-        {22.50000, 0.02450},
-        {23.00000, 0.00910},
-        {23.50000, 0.00320},
-        {24.00000, 0.00098},
-        {24.50000, 0.00033},
-        {25.00000, 0.00014},
-        {25.50000, 0.00004},
-        {26.00000, 0.00000},
-    },
-    // MCS-9
-    {
-        {19.00000, 1.00000},
-        {19.50000, 0.99800},
-        {20.00000, 0.98910},
-        {20.50000, 0.95970},
-        {21.00000, 0.87500},
-        {21.50000, 0.73170},
-        {22.00000, 0.51540},
-        {22.50000, 0.30380},
-        {23.00000, 0.15240},
-        {23.50000, 0.06340},
-        {24.00000, 0.02470},
-        {24.50000, 0.00850},
-        {25.00000, 0.00290},
-        {25.50000, 0.00100},
-        {26.00000, 0.00017},
-        {26.50000, 0.00014},
-        {27.00000, 0.00002},
-        {27.50000, 0.00000},
-    },
-};
+extern const SnrPerTable AwgnErrorTableBcc32[ERROR_TABLE_BCC_MAX_NUM_MCS];
 
 /// AWGN error table for BCC with reference size of 1458 bytes
-static const SnrPerTable AwgnErrorTableBcc1458[ERROR_TABLE_BCC_MAX_NUM_MCS] = {
-    // MCS-0
-    {
-        {-1.00000, 1.00000},
-        {-0.50000, 0.99400},
-        {0.00000, 0.81850},
-        {0.50000, 0.29080},
-        {1.00000, 0.06630},
-        {1.50000, 0.01120},
-        {2.00000, 0.00150},
-        {2.50000, 0.00015},
-        {3.00000, 0.00001},
-        {3.50000, 0.00000},
-    },
-    // MCS-1
-    {
-        {2.00000, 1.00000},
-        {2.50000, 0.99700},
-        {3.00000, 0.79440},
-        {3.50000, 0.30080},
-        {4.00000, 0.07280},
-        {4.50000, 0.01200},
-        {5.00000, 0.00150},
-        {5.50000, 0.00023},
-        {6.00000, 0.00000},
-    },
-    // MCS-2
-    {
-        {4.50000, 1.00000},
-        {5.00000, 0.99800},
-        {5.50000, 0.75780},
-        {6.00000, 0.30100},
-        {6.50000, 0.06760},
-        {7.00000, 0.01220},
-        {7.50000, 0.00230},
-        {8.00000, 0.00035},
-        {8.50000, 0.00004},
-        {9.00000, 0.00000},
-    },
-    // MCS-3
-    {
-        {7.50000, 1.00000},
-        {8.00000, 0.99400},
-        {8.50000, 0.84050},
-        {9.00000, 0.43410},
-        {9.50000, 0.14190},
-        {10.00000, 0.03740},
-        {10.50000, 0.00860},
-        {11.00000, 0.00190},
-        {11.50000, 0.00036},
-        {12.00000, 0.00005},
-        {12.50000, 0.00000},
-    },
-    // MCS-4
-    {
-        {11.00000, 1.00000},
-        {11.50000, 0.92690},
-        {12.00000, 0.51390},
-        {12.50000, 0.18260},
-        {13.00000, 0.04650},
-        {13.50000, 0.01100},
-        {14.00000, 0.00260},
-        {14.50000, 0.00041},
-        {15.00000, 0.00010},
-        {15.50000, 0.00000},
-    },
-    // MCS-5
-    {
-        {14.50000, 1.00000},
-        {15.00000, 0.99900},
-        {15.50000, 0.94790},
-        {16.00000, 0.66250},
-        {16.50000, 0.29780},
-        {17.00000, 0.10580},
-        {17.50000, 0.03340},
-        {18.00000, 0.00910},
-        {18.50000, 0.00230},
-        {19.00000, 0.00064},
-        {19.50000, 0.00017},
-        {20.00000, 0.00002},
-        {20.50000, 0.00000},
-    },
-    // MCS-6
-    {
-        {16.00000, 1.00000},
-        {16.50000, 0.99500},
-        {17.00000, 0.87960},
-        {17.50000, 0.51390},
-        {18.00000, 0.20910},
-        {18.50000, 0.06390},
-        {19.00000, 0.01860},
-        {19.50000, 0.00460},
-        {20.00000, 0.00130},
-        {20.50000, 0.00023},
-        {21.00000, 0.00002},
-        {21.50000, 0.00000},
-    },
-    // MCS-7
-    {
-        {17.50000, 1.00000},
-        {18.00000, 0.97850},
-        {18.50000, 0.73930},
-        {19.00000, 0.33750},
-        {19.50000, 0.12340},
-        {20.00000, 0.03550},
-        {20.50000, 0.01000},
-        {21.00000, 0.00270},
-        {21.50000, 0.00050},
-        {22.00000, 0.00009},
-        {22.50000, 0.00001},
-        {23.00000, 0.00000},
-    },
-    // MCS-8
-    {
-        {21.00000, 1.00000},
-        {21.50000, 0.99800},
-        {22.00000, 0.93990},
-        {22.50000, 0.67090},
-        {23.00000, 0.35250},
-        {23.50000, 0.13760},
-        {24.00000, 0.04750},
-        {24.50000, 0.01540},
-        {25.00000, 0.00520},
-        {25.50000, 0.00150},
-        {26.00000, 0.00036},
-        {26.50000, 0.00007},
-        {27.00000, 0.00000},
-    },
-    // MCS-9
-    {
-        {22.50000, 1.00000},
-        {23.00000, 0.99900},
-        {23.50000, 0.95060},
-        {24.00000, 0.68470},
-        {24.50000, 0.32610},
-        {25.00000, 0.12480},
-        {25.50000, 0.04090},
-        {26.00000, 0.01300},
-        {26.50000, 0.00360},
-        {27.00000, 0.00082},
-        {27.50000, 0.00010},
-        {28.00000, 0.00002},
-        {28.50000, 0.00001},
-        {29.00000, 0.00000},
-    },
-};
+extern const SnrPerTable AwgnErrorTableBcc1458[ERROR_TABLE_BCC_MAX_NUM_MCS];
 
 /// AWGN error table for LDPC with reference size of 1458 bytes
-static const SnrPerTable AwgnErrorTableLdpc1458[ERROR_TABLE_LDPC_MAX_NUM_MCS] = {
-    // MCS-0
-    {
-        {-1.50000, 1.00000},
-        {-1.25000, 0.97950},
-        {-1.00000, 0.60480},
-        {-0.75000, 0.17050},
-        {-0.50000, 0.03320},
-        {-0.25000, 0.00530},
-        {0.00000, 0.00085},
-        {0.25000, 0.00022},
-        {0.50000, 0.00004},
-        {0.75000, 0.00000},
-    },
-    // MCS-1
-    {
-        {1.50000, 1.00000},
-        {1.75000, 0.97470},
-        {2.00000, 0.62330},
-        {2.25000, 0.18590},
-        {2.50000, 0.03400},
-        {2.75000, 0.00550},
-        {3.00000, 0.00083},
-        {3.25000, 0.00015},
-        {3.50000, 0.00003},
-        {3.75000, 0.00000},
-    },
-    // MCS-2
-    {
-        {4.00000, 1.00000},
-        {4.25000, 0.98720},
-        {4.50000, 0.62560},
-        {4.75000, 0.15800},
-        {5.00000, 0.02090},
-        {5.25000, 0.00250},
-        {5.50000, 0.00034},
-        {5.75000, 0.00003},
-        {6.00000, 0.00000},
-    },
-    // MCS-3
-    {
-        {6.75000, 1.00000},
-        {7.00000, 0.99800},
-        {7.25000, 0.94340},
-        {7.50000, 0.57890},
-        {7.75000, 0.20640},
-        {8.00000, 0.04840},
-        {8.25000, 0.00930},
-        {8.50000, 0.00180},
-        {8.75000, 0.00040},
-        {9.00000, 0.00011},
-        {9.25000, 0.00002},
-        {9.50000, 0.00000},
-    },
-    // MCS-4
-    {{10.00000, 1.00000},
-     {10.25000, 0.99310},
-     {10.50000, 0.70890},
-     {10.75000, 0.24720},
-     {11.00000, 0.04700},
-     {11.25000, 0.00590},
-     {11.50000, 0.00091},
-     {11.75000, 0.00016},
-     {12.00000, 0.00003},
-     {12.25000, 0.00000}},
-    // MCS-5
-    {
-        {14.00000, 1.00000},
-        {14.25000, 0.99700},
-        {14.50000, 0.91830},
-        {14.75000, 0.53790},
-        {15.00000, 0.16610},
-        {15.25000, 0.03690},
-        {15.50000, 0.00650},
-        {15.75000, 0.00100},
-        {16.00000, 0.00031},
-        {16.25000, 0.00005},
-        {16.50000, 0.00000},
-    },
-    // MCS-6
-    {
-        {15.50000, 1.00000},
-        {15.75000, 0.98140},
-        {16.00000, 0.73930},
-        {16.25000, 0.33110},
-        {16.50000, 0.08150},
-        {16.75000, 0.01620},
-        {17.00000, 0.00270},
-        {17.25000, 0.00052},
-        {17.50000, 0.00005},
-        {17.75000, 0.00003},
-        {18.00000, 0.00000},
-    },
-    // MCS-7
-    {
-        {17.00000, 1.00000},
-        {17.25000, 0.97750},
-        {17.50000, 0.73980},
-        {17.75000, 0.33190},
-        {18.00000, 0.09640},
-        {18.25000, 0.02180},
-        {18.50000, 0.00470},
-        {18.75000, 0.00087},
-        {19.00000, 0.00018},
-        {19.25000, 0.00003},
-        {19.50000, 0.00000},
-    },
-    // MCS-8
-    {
-        {20.50000, 1.00000},
-        {20.75000, 0.99500},
-        {21.00000, 0.89700},
-        {21.25000, 0.56270},
-        {21.50000, 0.20920},
-        {21.75000, 0.05600},
-        {22.00000, 0.01170},
-        {22.25000, 0.00250},
-        {22.50000, 0.00038},
-        {22.75000, 0.00013},
-        {23.00000, 0.00004},
-        {23.25000, 0.00001},
-        {23.50000, 0.00000},
-    },
-    // MCS-9
-    {
-        {22.25000, 1.00000},
-        {22.50000, 0.99900},
-        {22.75000, 0.94080},
-        {23.00000, 0.63600},
-        {23.25000, 0.27190},
-        {23.50000, 0.08700},
-        {23.75000, 0.02210},
-        {24.00000, 0.00500},
-        {24.25000, 0.00110},
-        {24.50000, 0.00032},
-        {24.75000, 0.00004},
-        {25.00000, 0.00000},
-    },
-    // MCS-10
-    {
-        {25.75000, 1.00000},
-        {26.00000, 0.94970},
-        {26.25000, 0.68660},
-        {26.50000, 0.32940},
-        {26.75000, 0.11620},
-        {27.00000, 0.03440},
-        {27.25000, 0.00880},
-        {27.50000, 0.00210},
-        {27.75000, 0.00054},
-        {28.00000, 0.00009},
-        {28.25000, 0.00002},
-        {28.50000, 0.00000},
-    },
-    // MCS-11
-    {
-        {27.75000, 1.00000},
-        {28.00000, 0.94880},
-        {28.25000, 0.75260},
-        {28.50000, 0.40230},
-        {28.75000, 0.16210},
-        {29.00000, 0.05150},
-        {29.25000, 0.01310},
-        {29.50000, 0.00360},
-        {29.75000, 0.00100},
-        {30.00000, 0.00022},
-        {30.25000, 0.00006},
-        {30.50000, 0.00000},
-    },
-};
+extern const SnrPerTable AwgnErrorTableLdpc1458[ERROR_TABLE_LDPC_MAX_NUM_MCS];
 
 } // namespace ns3
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/spectrum-wifi-phy.cc ns-3.42/src/wifi/model/spectrum-wifi-phy.cc
--- ns-3.41/src/wifi/model/spectrum-wifi-phy.cc	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/spectrum-wifi-phy.cc	2024-05-29 15:29:47.208073900 -0700
@@ -41,6 +41,9 @@
 
 #include <algorithm>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(Ptr(this))
+
 namespace ns3
 {
 
@@ -85,10 +88,11 @@
                 DoubleValue(-40.0),
                 MakeDoubleAccessor(&SpectrumWifiPhy::m_txMaskOuterBandMaximumRejection),
                 MakeDoubleChecker<double>())
-            .AddTraceSource("SignalArrival",
-                            "Signal arrival",
-                            MakeTraceSourceAccessor(&SpectrumWifiPhy::m_signalCb),
-                            "ns3::SpectrumWifiPhy::SignalArrivalCallback");
+            .AddTraceSource(
+                "SignalArrival",
+                "Trace start of all signal arrivals, including weak and foreign signals",
+                MakeTraceSourceAccessor(&SpectrumWifiPhy::m_signalCb),
+                "ns3::SpectrumWifiPhy::SignalArrivalCallback");
     return tid;
 }
 
@@ -134,7 +138,7 @@
     }
     else
     {
-        for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
+        for (uint16_t bw = channelWidth; bw >= 20; bw = bw / 2)
         {
             for (uint32_t i = 0; i < (channelWidth / bw); ++i)
             {
@@ -151,7 +155,7 @@
 {
     HeRuBands heRuBands{};
     const auto channelWidth = spectrumPhyInterface->GetChannelWidth();
-    for (uint16_t bw = 160; bw >= 20; bw = bw / 2)
+    for (uint16_t bw = channelWidth; bw >= 20; bw = bw / 2)
     {
         for (uint32_t i = 0; i < (channelWidth / bw); ++i)
         {
@@ -403,6 +407,12 @@
     NS_LOG_FUNCTION(this << rxParams << interface);
     Time rxDuration = rxParams->duration;
     Ptr<SpectrumValue> receivedSignalPsd = rxParams->psd;
+    if (interface)
+    {
+        NS_ASSERT_MSG(receivedSignalPsd->GetValuesN() ==
+                          interface->GetRxSpectrumModel()->GetNumBands(),
+                      "Use multi model spectrum channel if PHYs have different spectrum models!");
+    }
     NS_LOG_DEBUG("Received signal with PSD " << *receivedSignalPsd << " and duration "
                                              << rxDuration.As(Time::NS));
     uint32_t senderNodeId = 0;
@@ -423,6 +433,8 @@
     double totalRxPowerW = 0;
     RxPowerWattPerChannelBand rxPowerW;
 
+    const auto rxGainRatio = DbToRatio(GetRxGain());
+
     std::size_t index = 0;
     uint16_t prevBw = 0;
     for (const auto& band : bands)
@@ -434,7 +446,7 @@
             WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
         NS_LOG_DEBUG("Signal power received (watts) before antenna gain for "
                      << bw << " MHz channel band " << index << ": " << band);
-        rxPowerPerBandW *= DbToRatio(GetRxGain());
+        rxPowerPerBandW *= rxGainRatio;
         rxPowerW.insert({band, rxPowerPerBandW});
         NS_LOG_DEBUG("Signal power received after antenna gain for "
                      << bw << " MHz channel band " << index << ": " << rxPowerPerBandW << " W ("
@@ -455,15 +467,7 @@
         {
             double rxPowerPerBandW =
                 WifiSpectrumValueHelper::GetBandPowerW(receivedSignalPsd, band.indices);
-            NS_LOG_DEBUG("Signal power received (watts) before antenna gain for RU with type "
-                         << ru.GetRuType() << " and index " << ru.GetIndex() << " -> ("
-                         << band.indices.first << "; " << band.indices.second
-                         << "): " << rxPowerPerBandW);
-            rxPowerPerBandW *= DbToRatio(GetRxGain());
-            NS_LOG_DEBUG("Signal power received after antenna gain for RU with type "
-                         << ru.GetRuType() << " and index " << ru.GetIndex() << " -> ("
-                         << band.indices.first << "; " << band.indices.second << "): "
-                         << rxPowerPerBandW << " W (" << WToDbm(rxPowerPerBandW) << " dBm)");
+            rxPowerPerBandW *= rxGainRatio;
             rxPowerW.insert({band, rxPowerPerBandW});
         }
     }
@@ -475,12 +479,15 @@
         DynamicCast<WifiSpectrumSignalParameters>(rxParams);
 
     // Log the signal arrival to the trace source
-    m_signalCb(bool(wifiRxParams), senderNodeId, WToDbm(totalRxPowerW), rxDuration);
+    m_signalCb(rxParams, senderNodeId, WToDbm(totalRxPowerW), rxDuration);
 
     if (!wifiRxParams)
     {
         NS_LOG_INFO("Received non Wi-Fi signal");
-        m_interference->AddForeignSignal(rxDuration, rxPowerW);
+        m_interference->AddForeignSignal(rxDuration,
+                                         rxPowerW,
+                                         interface ? interface->GetFrequencyRange()
+                                                   : GetCurrentFrequencyRange());
         SwitchMaybeToCcaBusy(nullptr);
         return;
     }
@@ -488,7 +495,8 @@
     if (wifiRxParams && m_disableWifiReception)
     {
         NS_LOG_INFO("Received Wi-Fi signal but blocked from syncing");
-        m_interference->AddForeignSignal(rxDuration, rxPowerW);
+        NS_ASSERT(interface);
+        m_interference->AddForeignSignal(rxDuration, rxPowerW, interface->GetFrequencyRange());
         SwitchMaybeToCcaBusy(nullptr);
         return;
     }
@@ -496,8 +504,9 @@
     if (m_trackSignalsInactiveInterfaces && interface &&
         (interface != m_currentSpectrumPhyInterface))
     {
-        NS_LOG_INFO("Received Wi-Fi signal from a non-active PHY interface");
-        m_interference->AddForeignSignal(rxDuration, rxPowerW);
+        NS_LOG_INFO("Received Wi-Fi signal from a non-active PHY interface "
+                    << interface->GetFrequencyRange());
+        m_interference->AddForeignSignal(rxDuration, rxPowerW, interface->GetFrequencyRange());
         SwitchMaybeToCcaBusy(nullptr);
         return;
     }
@@ -509,7 +518,7 @@
     if (totalRxPowerW < DbmToW(GetRxSensitivity()) * (ppdu->GetTxChannelWidth() / 20.0))
     {
         NS_LOG_INFO("Received signal too weak to process: " << WToDbm(totalRxPowerW) << " dBm");
-        m_interference->Add(ppdu, rxDuration, rxPowerW);
+        m_interference->Add(ppdu, rxDuration, rxPowerW, GetCurrentFrequencyRange());
         SwitchMaybeToCcaBusy(nullptr);
         return;
     }
@@ -519,7 +528,7 @@
         if (!CanStartRx(ppdu))
         {
             NS_LOG_INFO("Cannot start reception of the PPDU, consider it as interference");
-            m_interference->Add(ppdu, rxDuration, rxPowerW);
+            m_interference->Add(ppdu, rxDuration, rxPowerW, GetCurrentFrequencyRange());
             SwitchMaybeToCcaBusy(ppdu);
             return;
         }
@@ -563,6 +572,7 @@
 SpectrumWifiPhy::StartTx(Ptr<const WifiPpdu> ppdu)
 {
     NS_LOG_FUNCTION(this << ppdu);
+    m_signalTransmissionCb(ppdu, ppdu->GetTxVector());
     GetPhyEntity(ppdu->GetModulation())->StartTx(ppdu);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/spectrum-wifi-phy.h ns-3.42/src/wifi/model/spectrum-wifi-phy.h
--- ns-3.41/src/wifi/model/spectrum-wifi-phy.h	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/spectrum-wifi-phy.h	2024-05-29 15:29:47.208073900 -0700
@@ -124,12 +124,11 @@
     /**
      * Callback invoked when the PHY model starts to process a signal
      *
-     * \param signalType Whether signal is WiFi (true) or foreign (false)
      * \param senderNodeId Node Id of the sender of the signal
      * \param rxPower received signal power (dBm)
      * \param duration Signal duration
      */
-    typedef void (*SignalArrivalCallback)(bool signalType,
+    typedef void (*SignalArrivalCallback)(Ptr<const SpectrumSignalParameters> signal,
                                           uint32_t senderNodeId,
                                           double rxPower,
                                           Time duration);
@@ -286,7 +285,8 @@
     bool m_trackSignalsInactiveInterfaces; //!< flag whether signals coming from inactive spectrum
                                            //!< PHY interfaces are tracked
 
-    TracedCallback<bool, uint32_t, double, Time> m_signalCb; //!< Signal callback
+    TracedCallback<Ptr<const SpectrumSignalParameters>, uint32_t, double, Time>
+        m_signalCb; //!< Signal callback
 
     double m_txMaskInnerBandMinimumRejection; //!< The minimum rejection (in dBr) for the inner band
                                               //!< of the transmit spectrum mask
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/ssid.cc ns-3.42/src/wifi/model/ssid.cc
--- ns-3.41/src/wifi/model/ssid.cc	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/ssid.cc	2024-05-29 15:29:47.208073900 -0700
@@ -33,7 +33,7 @@
 
 Ssid::Ssid(std::string s)
 {
-    NS_ASSERT(s.size() < 32);
+    NS_ASSERT(s.size() <= 32);
     const char* ssid = s.c_str();
     uint8_t len = 0;
     while (*ssid != 0 && len < 32)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/sta-wifi-mac.cc ns-3.42/src/wifi/model/sta-wifi-mac.cc
--- ns-3.41/src/wifi/model/sta-wifi-mac.cc	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/sta-wifi-mac.cc	2024-05-29 15:29:47.208073900 -0700
@@ -45,7 +45,9 @@
 #include "ns3/simulator.h"
 #include "ns3/string.h"
 
+#include <iterator>
 #include <numeric>
+#include <sstream>
 
 namespace ns3
 {
@@ -207,6 +209,12 @@
     NS_LOG_FUNCTION(this);
 }
 
+void
+StaWifiMac::DoCompleteConfig()
+{
+    NS_LOG_FUNCTION(this);
+}
+
 StaWifiMac::StaLinkEntity::~StaLinkEntity()
 {
     NS_LOG_FUNCTION_NOARGS();
@@ -235,7 +243,9 @@
 {
     NS_LOG_FUNCTION(this << stream);
     m_probeDelay->SetStream(stream);
-    return 1;
+    auto currentStream = stream + 1;
+    currentStream += WifiMac::AssignStreams(currentStream);
+    return (currentStream - stream);
 }
 
 void
@@ -309,13 +319,18 @@
 void
 StaWifiMac::NotifyEmlsrModeChanged(const std::set<uint8_t>& linkIds)
 {
-    NS_LOG_FUNCTION(this << linkIds.size());
+    std::stringstream ss;
+    if (g_log.IsEnabled(ns3::LOG_FUNCTION))
+    {
+        std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+    }
+    NS_LOG_FUNCTION(this << ss.str());
 
     for (const auto& [linkId, lnk] : GetLinks())
     {
         auto& link = GetStaLink(lnk);
 
-        if (linkIds.count(linkId) > 0)
+        if (linkIds.contains(linkId))
         {
             // EMLSR mode enabled
             link.emlsrEnabled = true;
@@ -356,7 +371,7 @@
     auto supportedRates = GetSupportedRates(linkId);
     probe.Get<SupportedRates>() = supportedRates.rates;
     probe.Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
-    if (GetHtSupported())
+    if (GetHtSupported(linkId))
     {
         probe.Get<ExtendedCapabilities>() = GetExtendedCapabilities();
         probe.Get<HtCapabilities>() = GetHtCapabilities(linkId);
@@ -368,6 +383,10 @@
     if (GetHeSupported())
     {
         probe.Get<HeCapabilities>() = GetHeCapabilities(linkId);
+        if (Is6GhzBand(linkId))
+        {
+            probe.Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
+        }
     }
     if (GetEhtSupported())
     {
@@ -418,7 +437,7 @@
         frame.template Get<ExtendedSupportedRatesIE>() = supportedRates.extendedRates;
         frame.Capabilities() = GetCapabilities(linkId);
         frame.SetListenInterval(0);
-        if (GetHtSupported())
+        if (GetHtSupported(linkId))
         {
             frame.template Get<ExtendedCapabilities>() = GetExtendedCapabilities();
             frame.template Get<HtCapabilities>() = GetHtCapabilities(linkId);
@@ -430,6 +449,10 @@
         if (GetHeSupported())
         {
             frame.template Get<HeCapabilities>() = GetHeCapabilities(linkId);
+            if (Is6GhzBand(linkId))
+            {
+                frame.template Get<He6GhzBandCapabilities>() = GetHe6GhzBandCapabilities(linkId);
+            }
         }
         if (GetEhtSupported())
         {
@@ -484,7 +507,7 @@
     EnumValue<WifiTidToLinkMappingNegSupport> negSupport;
     ehtConfiguration->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
 
-    mldCapabilities->tidToLinkMappingSupport = negSupport.Get();
+    mldCapabilities->tidToLinkMappingSupport = static_cast<uint8_t>(negSupport.Get());
     mldCapabilities->freqSepForStrApMld = 0; // not supported yet
     mldCapabilities->aarSupport = 0;         // not supported yet
 
@@ -522,7 +545,7 @@
 }
 
 std::vector<TidToLinkMapping>
-StaWifiMac::GetTidToLinkMappingElements(uint8_t apNegSupport)
+StaWifiMac::GetTidToLinkMappingElements(WifiTidToLinkMappingNegSupport apNegSupport)
 {
     NS_LOG_FUNCTION(this << apNegSupport);
 
@@ -532,7 +555,7 @@
     EnumValue<WifiTidToLinkMappingNegSupport> negSupport;
     ehtConfig->GetAttributeFailSafe("TidToLinkMappingNegSupport", negSupport);
 
-    NS_ABORT_MSG_IF(negSupport.Get() == 0,
+    NS_ABORT_MSG_IF(negSupport.Get() == WifiTidToLinkMappingNegSupport::NOT_SUPPORTED,
                     "Cannot request TID-to-Link Mapping if negotiation is not supported");
 
     // store the mappings, so that we can enforce them when the AP MLD accepts them
@@ -542,10 +565,11 @@
     bool mappingValidForNegType1 = TidToLinkMappingValidForNegType1(m_dlTidLinkMappingInAssocReq,
                                                                     m_ulTidLinkMappingInAssocReq);
     NS_ABORT_MSG_IF(
-        negSupport.Get() == 1 && !mappingValidForNegType1,
+        negSupport.Get() == WifiTidToLinkMappingNegSupport::SAME_LINK_SET &&
+            !mappingValidForNegType1,
         "Mapping TIDs to distinct link sets is incompatible with negotiation support of 1");
 
-    if (apNegSupport == 1 && !mappingValidForNegType1)
+    if (apNegSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET && !mappingValidForNegType1)
     {
         // If the TID-to-link Mapping Negotiation Support subfield value received from a peer
         // MLD is equal to 1, the MLD that initiates a TID-to-link mapping negotiation with the
@@ -635,10 +659,12 @@
         };
         std::visit(addMle, frame);
 
-        uint8_t negSupport;
+        WifiTidToLinkMappingNegSupport negSupport;
         if (const auto& mldCapabilities =
                 GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(*link.bssid);
-            mldCapabilities && (negSupport = mldCapabilities->get().tidToLinkMappingSupport) > 0)
+            mldCapabilities && (negSupport = static_cast<WifiTidToLinkMappingNegSupport>(
+                                    mldCapabilities->get().tidToLinkMappingSupport)) >
+                                   WifiTidToLinkMappingNegSupport::NOT_SUPPORTED)
         {
             auto addTlm = [&](auto&& frame) {
                 frame.template Get<TidToLinkMapping>() = GetTidToLinkMappingElements(negSupport);
@@ -676,7 +702,7 @@
         GetVOQueue()->Queue(packet, hdr);
     }
 
-    if (m_assocRequestEvent.IsRunning())
+    if (m_assocRequestEvent.IsPending())
     {
         m_assocRequestEvent.Cancel();
     }
@@ -711,7 +737,6 @@
            wait until either assoc-request-timeout or until
            we get an association response.
          */
-        break;
     case REFUSED:
         /* we have sent an association request and received a negative
            association response. We wait until someone restarts an
@@ -837,7 +862,7 @@
 
     if (m_beaconWatchdogEnd > Simulator::Now())
     {
-        if (m_beaconWatchdog.IsRunning())
+        if (m_beaconWatchdog.IsPending())
         {
             m_beaconWatchdog.Cancel();
         }
@@ -1055,14 +1080,18 @@
 }
 
 void
-StaWifiMac::UnblockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason)
+StaWifiMac::UnblockTxOnLink(std::set<uint8_t> linkIds, WifiQueueBlockedReason reason)
 {
-    NS_LOG_FUNCTION(this << linkId << reason);
-
-    auto bssid = GetBssid(linkId);
-    auto apAddress = GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
+    std::stringstream ss;
+    std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+    NS_LOG_FUNCTION(this << ss.str() << reason);
+
+    const auto linkId = *linkIds.cbegin();
+    const auto bssid = GetBssid(linkId);
+    const auto apAddress =
+        GetWifiRemoteStationManager(linkId)->GetMldAddress(bssid).value_or(bssid);
 
-    UnblockUnicastTxOnLinks(reason, apAddress, {linkId});
+    UnblockUnicastTxOnLinks(reason, apAddress, linkIds);
     // the only type of broadcast frames that a non-AP STA can send are management frames
     for (const auto& [acIndex, ac] : wifiAcList)
     {
@@ -1072,7 +1101,7 @@
                                               Mac48Address::GetBroadcast(),
                                               GetFrameExchangeManager(linkId)->GetAddress(),
                                               {},
-                                              {linkId});
+                                              linkIds);
     }
 }
 
@@ -1116,7 +1145,7 @@
         {
             apAddresses.insert(GetBssid(id));
         }
-        if (apAddresses.count(mpdu->GetHeader().GetAddr2()) == 0)
+        if (!apAddresses.contains(mpdu->GetHeader().GetAddr2()))
         {
             NS_LOG_LOGIC("Received data frame not from the BSS we are associated with: ignore");
             NotifyRxDrop(packet);
@@ -1132,7 +1161,7 @@
         {
             if (hdr->IsQosAmsdu())
             {
-                NS_ASSERT(apAddresses.count(mpdu->GetHeader().GetAddr3()) != 0);
+                NS_ASSERT(apAddresses.contains(mpdu->GetHeader().GetAddr3()));
                 DeaggregateAmsduAndForward(mpdu);
                 packet = nullptr;
             }
@@ -1295,7 +1324,7 @@
     std::optional<Mac48Address> apMldAddress;
     MgtAssocResponseHeader assocResp;
     mpdu->GetPacket()->PeekHeader(assocResp);
-    if (m_assocRequestEvent.IsRunning())
+    if (m_assocRequestEvent.IsPending())
     {
         m_assocRequestEvent.Cancel();
     }
@@ -1316,7 +1345,9 @@
 
             if (const auto& mldCapabilities =
                     GetWifiRemoteStationManager(linkId)->GetStationMldCapabilities(hdr.GetAddr3());
-                mldCapabilities && mldCapabilities->get().tidToLinkMappingSupport > 0)
+                mldCapabilities && static_cast<WifiTidToLinkMappingNegSupport>(
+                                       mldCapabilities->get().tidToLinkMappingSupport) >
+                                       WifiTidToLinkMappingNegSupport::NOT_SUPPORTED)
             {
                 // the AP MLD supports TID-to-Link Mapping negotiation, hence we included
                 // TID-to-Link Mapping element(s) in the Association Request.
@@ -1456,7 +1487,7 @@
                                             Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
                                             Txop::CHECK_MEDIUM_BUSY);
             }
-            for (const auto [acIndex, ac] : wifiAcList)
+            for (const auto& [acIndex, ac] : wifiAcList)
             {
                 if (const auto edca = GetQosTxop(acIndex))
                 {
@@ -1682,26 +1713,22 @@
         }
         GetWifiRemoteStationManager(linkId)->SetQosSupport(apAddr, qosSupported);
 
-        if (!GetHtSupported())
-        {
-            return;
-        }
-        /* HT station */
-        if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
-            htCapabilities.has_value())
+        if (GetHtSupported(linkId))
         {
-            if (!htCapabilities->IsSupportedMcs(0))
+            /* HT station */
+            if (const auto& htCapabilities = frame.template Get<HtCapabilities>();
+                htCapabilities.has_value())
             {
-                GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
+                GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
+                                                                              *htCapabilities);
             }
             else
             {
-                GetWifiRemoteStationManager(linkId)->AddStationHtCapabilities(apAddr,
-                                                                              *htCapabilities);
+                GetWifiRemoteStationManager(linkId)->RemoveAllSupportedMcs(apAddr);
             }
+            // TODO: process ExtendedCapabilities
+            // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
         }
-        // TODO: process ExtendedCapabilities
-        // ExtendedCapabilities extendedCapabilities = frame.GetExtendedCapabilities ();
 
         // we do not return if VHT is not supported because HE STAs operating in
         // the 2.4 GHz band do not support VHT
@@ -1745,8 +1772,9 @@
             if (const auto& heOperation = frame.template Get<HeOperation>();
                 heOperation.has_value())
             {
-                GetHeConfiguration()->SetAttribute("BssColor",
-                                                   UintegerValue(heOperation->GetBssColor()));
+                GetHeConfiguration()->SetAttribute(
+                    "BssColor",
+                    UintegerValue(heOperation->m_bssColorInfo.m_bssColor));
             }
         }
 
@@ -1779,6 +1807,16 @@
                                 linkId);
         }
 
+        if (Is6GhzBand(linkId))
+        {
+            if (const auto& he6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>())
+            {
+                GetWifiRemoteStationManager(linkId)->AddStationHe6GhzCapabilities(
+                    apAddr,
+                    *he6GhzCapabilities);
+            }
+        }
+
         if (!GetEhtSupported())
         {
             return;
@@ -1923,7 +1961,7 @@
         NS_LOG_DEBUG("Adding supported rate of " << modeDataRate);
         rates.AddSupportedRate(modeDataRate);
     }
-    if (GetHtSupported())
+    if (GetHtSupported(linkId))
     {
         for (const auto& selector : GetWifiPhy(linkId)->GetBssMembershipSelectorList())
         {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/sta-wifi-mac.h ns-3.42/src/wifi/model/sta-wifi-mac.h
--- ns-3.41/src/wifi/model/sta-wifi-mac.h	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/sta-wifi-mac.h	2024-05-29 15:29:47.208073900 -0700
@@ -25,6 +25,8 @@
 #include "mgt-headers.h"
 #include "wifi-mac.h"
 
+#include "ns3/eht-configuration.h"
+
 #include <set>
 #include <variant>
 
@@ -108,7 +110,7 @@
      │                │ ┌─────────────────────────────────────┐  │    │
      │                │ │                                     │  │    │
      │  ┌─────────────▼─▼──┐       ┌──────────────┐       ┌───┴──▼────┴───────────────────┐
-     └──►   Unassociated   ├───────►   Scanning   ├───────►   Wait AssociationiResponse   │
+     └──►   Unassociated   ├───────►   Scanning   ├───────►   Wait Association Response   │
         └──────────────────┘       └──────┬──▲────┘       └───────────────┬──▲────────────┘
                                           │  │                            │  │
                                           │  │                            │  │
@@ -195,6 +197,7 @@
      */
     void Enqueue(Ptr<Packet> packet, Mac48Address to) override;
     bool CanForwardPacketsTo(Mac48Address to) const override;
+    int64_t AssignStreams(int64_t stream) override;
 
     /**
      * \param phys the physical layers attached to this MAC.
@@ -320,23 +323,12 @@
     void BlockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason);
 
     /**
-     * Unblock transmissions on the given link for the given reason.
-     *
-     * \param linkId the ID of the given link
-     * \param reason the reason for unblocking transmissions on the given link
-     */
-    void UnblockTxOnLink(uint8_t linkId, WifiQueueBlockedReason reason);
-
-    /**
-     * Assign a fixed random variable stream number to the random variables
-     * used by this model.  Return the number of streams (possibly zero) that
-     * have been assigned.
+     * Unblock transmissions on the given links for the given reason.
      *
-     * \param stream first stream index to use
-     *
-     * \return the number of stream indices assigned by this model
+     * \param linkIds the IDs of the given links
+     * \param reason the reason for unblocking transmissions on the given links
      */
-    int64_t AssignStreams(int64_t stream);
+    void UnblockTxOnLink(std::set<uint8_t> linkIds, WifiQueueBlockedReason reason);
 
   protected:
     /**
@@ -388,6 +380,8 @@
     };
 
   private:
+    void DoCompleteConfig() override;
+
     /**
      * Enable or disable active probing.
      *
@@ -534,7 +528,8 @@
      * \param apNegSupport the negotiation type supported by the AP MLD
      * \return the TID-to-Link Mapping element(s) to include in Association Request frame.
      */
-    std::vector<TidToLinkMapping> GetTidToLinkMappingElements(uint8_t apNegSupport);
+    std::vector<TidToLinkMapping> GetTidToLinkMappingElements(
+        WifiTidToLinkMappingNegSupport apNegSupport);
 
     /**
      * Set the current MAC state.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/tim.cc ns-3.42/src/wifi/model/tim.cc
--- ns-3.41/src/wifi/model/tim.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/tim.cc	2024-05-29 15:29:47.208073900 -0700
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Davide Magrin <davide@magr.in>
+ */
+
+#include "tim.h"
+
+#include <algorithm>
+#include <cstdint>
+
+namespace ns3
+{
+
+WifiInformationElementId
+Tim::ElementId() const
+{
+    return IE_TIM;
+}
+
+uint16_t
+Tim::GetInformationFieldSize() const
+{
+    // When the TIM is carried in a non-S1G PPDU, in the event that all bits other than bit 0 in
+    // the traffic indication virtual bitmap are 0, the Partial Virtual Bitmap field is encoded as
+    // a single octet equal to 0, the Bitmap Offset subfield is 0, and the Length field is 4.
+    // (Sec. 9.4.2.5.1 of 802.11-2020)
+    // The size of the information field is the size of the Partial Virtual Bitmap field,
+    // plus one octet each for the DTIM Count, DTIM Period, and Bitmap Control fields
+    uint16_t partialVirtualBitmapSize =
+        GetLastNonZeroOctetIndex() - GetPartialVirtualBitmapOffset() + 1;
+    return partialVirtualBitmapSize + 3;
+}
+
+void
+Tim::AddAid(uint16_t aid)
+{
+    NS_ABORT_IF(aid > 2007);
+
+    m_aidValues.insert(aid);
+}
+
+bool
+Tim::HasAid(uint16_t aid) const
+{
+    return m_aidValues.find(aid) != m_aidValues.end();
+}
+
+std::set<uint16_t>
+Tim::GetAidSet(uint16_t aid) const
+{
+    auto start = m_aidValues.upper_bound(aid);
+    return std::set<uint16_t>(start, m_aidValues.cend());
+}
+
+void
+Tim::SerializeInformationField(Buffer::Iterator start) const
+{
+    start.WriteU8(m_dtimCount);
+    start.WriteU8(m_dtimPeriod);
+
+    // the Bitmap Control field is optional if the TIM is carried in an S1G PPDU, while
+    // it is always present when the TIM is carried in a non-S1G PPDU
+    start.WriteU8(GetBitmapControl());
+    auto partialVirtualBitmap = GetPartialVirtualBitmap();
+    for (auto byte : partialVirtualBitmap)
+    {
+        start.WriteU8(byte);
+    }
+}
+
+uint16_t
+Tim::DeserializeInformationField(Buffer::Iterator start, uint16_t length)
+{
+    NS_ABORT_MSG_IF(length < 2, "Invalid length: " << length);
+
+    m_dtimCount = start.ReadU8();
+    m_dtimPeriod = start.ReadU8();
+
+    if (length == 2)
+    {
+        // no Bitmap Control field nor Partial Virtual Bitmap field
+        return 2;
+    }
+
+    // Bitmap control field: here we determine the presence of multicast traffic and the offset
+    auto bitmapControl = start.ReadU8();
+    // Least significant bit is the Traffic Indication field
+    m_hasMulticastPending = bitmapControl & 0x01;
+    // Other bits are the Bitmap Offset
+    uint8_t partialVirtualBitmapOffset = bitmapControl & 0xFE;
+    // Next, deserialize the partial virtual bitmap
+    uint16_t octetIndex;
+    // length is the length of the information fields, so we need to
+    // subtract 3 to get the length of the Partial Virtual Bitmap
+    for (octetIndex = partialVirtualBitmapOffset;
+         octetIndex < static_cast<uint16_t>(partialVirtualBitmapOffset + length - 3);
+         ++octetIndex)
+    {
+        if (auto octet = start.ReadU8(); octet > 0)
+        {
+            // Look for bits set to 1
+            for (uint8_t position = 0; position < 8; position++)
+            {
+                if ((octet >> position) & 0x1)
+                {
+                    m_aidValues.insert(GetAidFromOctetIndexAndBitPosition(octetIndex, position));
+                }
+            }
+        }
+    }
+    return 3 + octetIndex - partialVirtualBitmapOffset;
+}
+
+uint8_t
+Tim::GetAidOctetIndex(uint16_t aid) const
+{
+    // bit number N (0 <= N <= 2007) in the bitmap corresponds to bit number (N mod 8) in octet
+    // number |_N / 8_| where the low order bit of each octet is bit number 0, and the high order
+    // bit is bit number 7 (Sec. 9.4.2.5.1 of 802.11-2020)
+    return (aid >> 3) & 0xff;
+}
+
+uint8_t
+Tim::GetAidBit(uint16_t aid) const
+{
+    // bit number N (0 <= N <= 2007) in the bitmap corresponds to bit number (N mod 8) in octet
+    // number |_N / 8_| where the low order bit of each octet is bit number 0, and the high order
+    // bit is bit number 7 (Sec. 9.4.2.5.1 of 802.11-2020)
+    return 0x01 << (aid & 0x07);
+}
+
+uint16_t
+Tim::GetAidFromOctetIndexAndBitPosition(uint16_t octet, uint8_t position) const
+{
+    return (octet << 3) + position;
+}
+
+uint8_t
+Tim::GetPartialVirtualBitmapOffset() const
+{
+    if (m_aidValues.empty())
+    {
+        return 0;
+    }
+    // N1 is the largest even number such that bits numbered 1 to (N1 * 8) – 1 in the traffic
+    // indication virtual bitmap are all 0 (Sec. 9.4.2.5.1 of 802.11-2020).
+    // Examples:
+    // first bit set = 53, which belongs to octet 53 / 8 = 6 -> N1 = 6 (all bits 1 - 47 are zero)
+    // first bit set = 61, which belongs to octet 61 / 8 = 7 -> N1 = 6 (all bits 1 - 47 are zero)
+    return GetAidOctetIndex(*m_aidValues.cbegin()) & 0xFE;
+}
+
+uint8_t
+Tim::GetLastNonZeroOctetIndex() const
+{
+    if (m_aidValues.empty())
+    {
+        return 0;
+    }
+    // N2 is the smallest number such that bits numbered (N2 + 1) * 8 to 2007 in the traffic
+    // indication virtual bitmap are all 0 (Sec. 9.4.2.5.1 of 802.11-2020).
+    // Examples:
+    // last bit set = 53, which belongs to octet 53 / 8 = 6 -> N2 = 6 (all bits 56 - 2007 are zero)
+    // last bit set = 61, which belongs to octet 61 / 8 = 7 -> N2 = 7 (all bits 64 - 2007 are zero)
+    return GetAidOctetIndex(*m_aidValues.rbegin());
+}
+
+uint8_t
+Tim::GetBitmapControl() const
+{
+    // Note that setting the bitmapControl directly as the offset can be done because the least
+    // significant bit of the output of GetPartialVirtualBitmapOffset will always be zero, so we
+    // are already putting the relevant information in the appropriate part of the byte.
+    auto bitmapControl = GetPartialVirtualBitmapOffset();
+
+    // Set the multicast indication bit, if this is a DTIM
+    if ((m_dtimCount == 0) && m_hasMulticastPending)
+    {
+        bitmapControl |= 0x01;
+    }
+
+    return bitmapControl;
+}
+
+std::vector<uint8_t>
+Tim::GetPartialVirtualBitmap() const
+{
+    auto offset = GetPartialVirtualBitmapOffset(); // N1
+
+    // the Partial Virtual Bitmap field consists of octets numbered N1 to N2 of the traffic
+    // indication virtual bitmap (Sec. 9.4.2.5.1 of 802.11-2020)
+    std::vector<uint8_t> partialVirtualBitmap(GetLastNonZeroOctetIndex() - offset + 1, 0);
+
+    for (auto aid : m_aidValues)
+    {
+        partialVirtualBitmap.at(GetAidOctetIndex(aid) - offset) |= GetAidBit(aid);
+    }
+
+    return partialVirtualBitmap;
+}
+
+void
+Tim::Print(std::ostream& os) const
+{
+    os << "DTIM Count: " << +m_dtimCount << ", "
+       << "DTIM Period: " << +m_dtimPeriod << ", "
+       << "Has Multicast Pending: " << m_hasMulticastPending << ", AID values:";
+    for (uint16_t aid = 0; aid < 2008; ++aid)
+    {
+        if (HasAid(aid))
+        {
+            os << aid << " ";
+        }
+    }
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/tim.h ns-3.42/src/wifi/model/tim.h
--- ns-3.41/src/wifi/model/tim.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/tim.h	2024-05-29 15:29:47.208073900 -0700
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Davide Magrin <davide@magr.in>
+ */
+
+#ifndef TIM_H
+#define TIM_H
+
+#include "wifi-information-element.h"
+
+#include <set>
+
+namespace ns3
+{
+
+/**
+ * \brief The Traffic Indication Map Information Element
+ * \ingroup wifi
+ *
+ * The 802.11 Traffic Indication Map (see section 9.4.2.5 of 802.11-2020)
+ *
+ * Note: The current implementation does not support S1G operation, or
+ * multiple BSSID.
+ */
+class Tim : public WifiInformationElement
+{
+  public:
+    WifiInformationElementId ElementId() const override;
+    void Print(std::ostream& os) const override;
+
+    /**
+     * Add the provided AID value to the list contained in the Virtual Bitmap
+     *
+     * \param aid the AID value to add to this TIM's Virtual Bitmap
+     */
+    void AddAid(uint16_t aid);
+
+    /**
+     * Add the AID values in the provided iterator range to the list contained
+     * in the Virtual Bitmap
+     *
+     * \tparam Iterator Type of iterator
+     * \param begin Starting position of the iterator range
+     * \param end Ending position of the iterator range
+     */
+    template <typename Iterator>
+    void AddAid(Iterator begin, Iterator end);
+
+    /**
+     * Check whether the bit corresponding to the provided AID is set in the
+     * Virtual Bitmap included in this TIM
+     *
+     * \param aid The AID value to look for
+     * \return True if the AID value is found in the Virtual Bitmap, false otherwise
+     */
+    bool HasAid(uint16_t aid) const;
+
+    /**
+     * Return the AID values, greater than the given AID value, whose corresponding bits are set
+     * in the virtual bitmap.
+     *
+     * \param aid the given AID value
+     * \return the AID values, greater than the given AID value, whose corresponding bits are set
+     *         in the virtual bitmap
+     */
+    std::set<uint16_t> GetAidSet(uint16_t aid = 0) const;
+
+    /**
+     * Get the Partial Virtual Bitmap offset, i.e., the number (denoted as N1 by the specs) of
+     * the first octet included in the Partial Virtual Bitmap. Note that the Bitmap Offset
+     * subfield contains the number N1/2.
+     *
+     * \return the Partial Virtual Bitmap offset
+     */
+    uint8_t GetPartialVirtualBitmapOffset() const;
+
+    /**
+     * \return the last non-zero octet in the virtual bitmap (denoted as N2 by the specs)
+     */
+    uint8_t GetLastNonZeroOctetIndex() const;
+
+    uint8_t m_dtimCount{0};            //!< The DTIM Count field
+    uint8_t m_dtimPeriod{0};           //!< The DTIM Period field
+    bool m_hasMulticastPending{false}; //!< Whether there is Multicast / Broadcast data
+
+  private:
+    uint16_t GetInformationFieldSize() const override;
+    void SerializeInformationField(Buffer::Iterator start) const override;
+    uint16_t DeserializeInformationField(Buffer::Iterator start, uint16_t length) override;
+
+    /**
+     * Obtain the index of the octet where the provided AID value should be
+     * set in the Virtual Bitmap
+     *
+     * \param aid the provided AID value
+     * \return the index of the octet where the provided AID value should be
+     *         set in the Virtual Bitmap
+     */
+    uint8_t GetAidOctetIndex(uint16_t aid) const;
+
+    /**
+     * Obtain an octet with a set bit, corresponding to the provided AID value
+     *
+     * \param aid the provided AID value
+     * \return an octet with a set bit, corresponding to the provided AID value
+     */
+    uint8_t GetAidBit(uint16_t aid) const;
+
+    /**
+     * Obtain the AID value represented by a certain octet index and bit
+     * position inside the Virtual Bitmap
+     *
+     * \param octet the octet index in the Virtual Bitmap
+     * \param position the bit position in the octet of the Virtual Bitmap
+     * \return the corresponding AID value
+     */
+    uint16_t GetAidFromOctetIndexAndBitPosition(uint16_t octet, uint8_t position) const;
+
+    /**
+     * The Bitmap Control field is optional if the TIM is carried in an S1G PPDU, while
+     * it is always present when the TIM is carried in a non-S1G PPDU.
+     *
+     * \return the value of the Bitmap Control field
+     */
+    uint8_t GetBitmapControl() const;
+
+    /**
+     * \return a vector containing the Partial Virtual Bitmap octets
+     */
+    std::vector<uint8_t> GetPartialVirtualBitmap() const;
+
+    std::set<uint16_t> m_aidValues; //!< List of AID values included in this TIM
+};
+
+template <typename Iterator>
+void
+Tim::AddAid(Iterator begin, Iterator end)
+{
+    for (auto& it = begin; it != end; it++)
+    {
+        AddAid(*it);
+    }
+}
+
+} // namespace ns3
+
+#endif /* TIM_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/txop.cc ns-3.42/src/wifi/model/txop.cc
--- ns-3.41/src/wifi/model/txop.cc	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/txop.cc	2024-05-29 15:29:47.208073900 -0700
@@ -25,20 +25,20 @@
 #include "wifi-mac-queue.h"
 #include "wifi-mac-trailer.h"
 #include "wifi-mac.h"
+#include "wifi-phy.h"
 
 #include "ns3/attribute-container.h"
 #include "ns3/log.h"
 #include "ns3/pointer.h"
-#include "ns3/random-variable-stream.h"
+#include "ns3/shuffle.h"
 #include "ns3/simulator.h"
 #include "ns3/socket.h"
 
+#include <iterator>
+#include <sstream>
+
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT                                                                      \
-    if (m_mac)                                                                                     \
-    {                                                                                              \
-        std::clog << "[mac=" << m_mac->GetAddress() << "] ";                                       \
-    }
+#define NS_LOG_APPEND_CONTEXT WIFI_TXOP_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
@@ -55,6 +55,27 @@
             .SetParent<ns3::Object>()
             .SetGroupName("Wifi")
             .AddConstructor<Txop>()
+            .AddAttribute("AcIndex",
+                          "The AC index of the packets contained in the wifi MAC queue of this "
+                          "Txop object.",
+                          EnumValue(AcIndex::AC_UNDEF),
+                          MakeEnumAccessor<AcIndex>(&Txop::CreateQueue),
+                          MakeEnumChecker(AC_BE,
+                                          "AC_BE",
+                                          AC_BK,
+                                          "AC_BK",
+                                          AC_VI,
+                                          "AC_VI",
+                                          AC_VO,
+                                          "AC_VO",
+                                          AC_BE_NQOS,
+                                          "AC_BE_NQOS",
+                                          AC_VI,
+                                          "AC_VI",
+                                          AC_BEACON,
+                                          "AC_BEACON",
+                                          AC_UNDEF,
+                                          "AC_UNDEF"))
             .AddAttribute("MinCw",
                           "The minimum value of the contention window (just for the first link, "
                           "in case of 11be multi-link devices).",
@@ -62,11 +83,16 @@
                           UintegerValue(15),
                           MakeUintegerAccessor((void(Txop::*)(uint32_t)) & Txop::SetMinCw,
                                                (uint32_t(Txop::*)() const) & Txop::GetMinCw),
-                          MakeUintegerChecker<uint32_t>())
+                          MakeUintegerChecker<uint32_t>(),
+                          TypeId::OBSOLETE,
+                          "Use MinCws attribute instead of MinCw")
             .AddAttribute(
                 "MinCws",
-                "The minimum values of the contention window for all the links",
-                TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
+                "The minimum values of the contention window for all the links (sorted in "
+                "increasing order of link ID). An empty vector is ignored and the default value "
+                "as per Table 9-155 of the IEEE 802.11-2020 standard will be used. Note that, if "
+                "this is a non-AP STA, these values could be overridden by values advertised by "
+                "the AP through EDCA Parameter Set elements.",
                 AttributeContainerValue<UintegerValue>(),
                 MakeAttributeContainerAccessor<UintegerValue>(&Txop::SetMinCws, &Txop::GetMinCws),
                 MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint32_t>()))
@@ -77,11 +103,16 @@
                           UintegerValue(1023),
                           MakeUintegerAccessor((void(Txop::*)(uint32_t)) & Txop::SetMaxCw,
                                                (uint32_t(Txop::*)() const) & Txop::GetMaxCw),
-                          MakeUintegerChecker<uint32_t>())
+                          MakeUintegerChecker<uint32_t>(),
+                          TypeId::OBSOLETE,
+                          "Use MaxCws attribute instead of MaxCw")
             .AddAttribute(
                 "MaxCws",
-                "The maximum values of the contention window for all the links",
-                TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
+                "The maximum values of the contention window for all the links (sorted in "
+                "increasing order of link ID). An empty vector is ignored and the default value "
+                "as per Table 9-155 of the IEEE 802.11-2020 standard will be used. Note that, if "
+                "this is a non-AP STA, these values could be overridden by values advertised by "
+                "the AP through EDCA Parameter Set elements.",
                 AttributeContainerValue<UintegerValue>(),
                 MakeAttributeContainerAccessor<UintegerValue>(&Txop::SetMaxCws, &Txop::GetMaxCws),
                 MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint32_t>()))
@@ -93,11 +124,16 @@
                 UintegerValue(2),
                 MakeUintegerAccessor((void(Txop::*)(uint8_t)) & Txop::SetAifsn,
                                      (uint8_t(Txop::*)() const) & Txop::GetAifsn),
-                MakeUintegerChecker<uint8_t>())
+                MakeUintegerChecker<uint8_t>(),
+                TypeId::OBSOLETE,
+                "Use Aifsns attribute instead of Aifsn")
             .AddAttribute(
                 "Aifsns",
-                "The values of AIFSN for all the links",
-                TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
+                "The values of AIFSN for all the links (sorted in increasing order "
+                "of link ID). An empty vector is ignored and the default value as per "
+                "Table 9-155 of the IEEE 802.11-2020 standard will be used. Note that, if "
+                "this is a non-AP STA, these values could be overridden by values advertised by "
+                "the AP through EDCA Parameter Set elements.",
                 AttributeContainerValue<UintegerValue>(),
                 MakeAttributeContainerAccessor<UintegerValue>(&Txop::SetAifsns, &Txop::GetAifsns),
                 MakeAttributeContainerChecker<UintegerValue>(MakeUintegerChecker<uint8_t>()))
@@ -108,14 +144,20 @@
                           TimeValue(MilliSeconds(0)),
                           MakeTimeAccessor((void(Txop::*)(Time)) & Txop::SetTxopLimit,
                                            (Time(Txop::*)() const) & Txop::GetTxopLimit),
-                          MakeTimeChecker())
-            .AddAttribute("TxopLimits",
-                          "The values of TXOP limit for all the links",
-                          TypeId::ATTR_GET | TypeId::ATTR_SET, // do not set at construction time
-                          AttributeContainerValue<TimeValue>(),
-                          MakeAttributeContainerAccessor<TimeValue>(&Txop::SetTxopLimits,
-                                                                    &Txop::GetTxopLimits),
-                          MakeAttributeContainerChecker<TimeValue>(MakeTimeChecker()))
+                          MakeTimeChecker(),
+                          TypeId::OBSOLETE,
+                          "Use TxopLimits attribute instead of TxopLimit")
+            .AddAttribute(
+                "TxopLimits",
+                "The values of TXOP limit for all the links (sorted in increasing order "
+                "of link ID). An empty vector is ignored and the default value as per "
+                "Table 9-155 of the IEEE 802.11-2020 standard will be used. Note that, if "
+                "this is a non-AP STA, these values could be overridden by values advertised by "
+                "the AP through EDCA Parameter Set elements.",
+                AttributeContainerValue<TimeValue>(),
+                MakeAttributeContainerAccessor<TimeValue>(&Txop::SetTxopLimits,
+                                                          &Txop::GetTxopLimits),
+                MakeAttributeContainerChecker<TimeValue>(MakeTimeChecker()))
             .AddAttribute("Queue",
                           "The WifiMacQueue object",
                           PointerValue(),
@@ -133,15 +175,9 @@
 }
 
 Txop::Txop()
-    : Txop(CreateObject<WifiMacQueue>(AC_BE_NQOS))
-{
-}
-
-Txop::Txop(Ptr<WifiMacQueue> queue)
-    : m_queue(queue)
 {
     NS_LOG_FUNCTION(this);
-    m_rng = CreateObject<UniformRandomVariable>();
+    m_rng = m_shuffleLinkIdsGen.GetRv();
 }
 
 Txop::~Txop()
@@ -160,6 +196,14 @@
     m_links.clear();
 }
 
+void
+Txop::CreateQueue(AcIndex aci)
+{
+    NS_LOG_FUNCTION(this << aci);
+    NS_ABORT_MSG_IF(m_queue, "Wifi MAC queue can only be created once");
+    m_queue = CreateObject<WifiMacQueue>(aci);
+}
+
 std::unique_ptr<Txop::LinkEntity>
 Txop::CreateLinkEntity() const
 {
@@ -240,9 +284,20 @@
 }
 
 void
-Txop::SetMinCws(std::vector<uint32_t> minCws)
+Txop::SetMinCws(const std::vector<uint32_t>& minCws)
 {
-    NS_ABORT_IF(minCws.size() != m_links.size());
+    if (minCws.empty())
+    {
+        // an empty vector is passed to use the default values specified by the standard
+        return;
+    }
+
+    NS_ABORT_MSG_IF(!m_links.empty() && minCws.size() != m_links.size(),
+                    "The size of the given vector (" << minCws.size()
+                                                     << ") does not match the number of links ("
+                                                     << m_links.size() << ")");
+    m_userAccessParams.cwMins = minCws;
+
     std::size_t i = 0;
     for (const auto& [id, link] : m_links)
     {
@@ -253,7 +308,9 @@
 void
 Txop::SetMinCw(uint32_t minCw, uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << minCw << +linkId);
+    NS_LOG_FUNCTION(this << minCw << linkId);
+    NS_ASSERT_MSG(!m_links.empty(),
+                  "This function can only be called after that links have been created");
     auto& link = GetLink(linkId);
     bool changed = (link.cwMin != minCw);
     link.cwMin = minCw;
@@ -270,9 +327,20 @@
 }
 
 void
-Txop::SetMaxCws(std::vector<uint32_t> maxCws)
+Txop::SetMaxCws(const std::vector<uint32_t>& maxCws)
 {
-    NS_ABORT_IF(maxCws.size() != m_links.size());
+    if (maxCws.empty())
+    {
+        // an empty vector is passed to use the default values specified by the standard
+        return;
+    }
+
+    NS_ABORT_MSG_IF(!m_links.empty() && maxCws.size() != m_links.size(),
+                    "The size of the given vector (" << maxCws.size()
+                                                     << ") does not match the number of links ("
+                                                     << m_links.size() << ")");
+    m_userAccessParams.cwMaxs = maxCws;
+
     std::size_t i = 0;
     for (const auto& [id, link] : m_links)
     {
@@ -283,7 +351,9 @@
 void
 Txop::SetMaxCw(uint32_t maxCw, uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << maxCw << +linkId);
+    NS_LOG_FUNCTION(this << maxCw << linkId);
+    NS_ASSERT_MSG(!m_links.empty(),
+                  "This function can only be called after that links have been created");
     auto& link = GetLink(linkId);
     bool changed = (link.cwMax != maxCw);
     link.cwMax = maxCw;
@@ -302,7 +372,7 @@
 void
 Txop::ResetCw(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this);
+    NS_LOG_FUNCTION(this << linkId);
     auto& link = GetLink(linkId);
     link.cw = GetMinCw(linkId);
     m_cwTrace(link.cw, linkId);
@@ -311,7 +381,7 @@
 void
 Txop::UpdateFailedCw(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this);
+    NS_LOG_FUNCTION(this << linkId);
     auto& link = GetLink(linkId);
     // see 802.11-2012, section 9.19.2.5
     link.cw = std::min(2 * (link.cw + 1) - 1, GetMaxCw(linkId));
@@ -335,7 +405,7 @@
 void
 Txop::UpdateBackoffSlotsNow(uint32_t nSlots, Time backoffUpdateBound, uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << nSlots << backoffUpdateBound << +linkId);
+    NS_LOG_FUNCTION(this << nSlots << backoffUpdateBound << linkId);
     auto& link = GetLink(linkId);
 
     link.backoffSlots -= nSlots;
@@ -346,7 +416,7 @@
 void
 Txop::StartBackoffNow(uint32_t nSlots, uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << nSlots << +linkId);
+    NS_LOG_FUNCTION(this << nSlots << linkId);
     auto& link = GetLink(linkId);
 
     if (link.backoffSlots != 0)
@@ -368,9 +438,20 @@
 }
 
 void
-Txop::SetAifsns(std::vector<uint8_t> aifsns)
+Txop::SetAifsns(const std::vector<uint8_t>& aifsns)
 {
-    NS_ABORT_IF(aifsns.size() != m_links.size());
+    if (aifsns.empty())
+    {
+        // an empty vector is passed to use the default values specified by the standard
+        return;
+    }
+
+    NS_ABORT_MSG_IF(!m_links.empty() && aifsns.size() != m_links.size(),
+                    "The size of the given vector (" << aifsns.size()
+                                                     << ") does not match the number of links ("
+                                                     << m_links.size() << ")");
+    m_userAccessParams.aifsns = aifsns;
+
     std::size_t i = 0;
     for (const auto& [id, link] : m_links)
     {
@@ -381,7 +462,9 @@
 void
 Txop::SetAifsn(uint8_t aifsn, uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +aifsn << +linkId);
+    NS_LOG_FUNCTION(this << aifsn << linkId);
+    NS_ASSERT_MSG(!m_links.empty(),
+                  "This function can only be called after that links have been created");
     GetLink(linkId).aifsn = aifsn;
 }
 
@@ -394,10 +477,18 @@
 void
 Txop::SetTxopLimits(const std::vector<Time>& txopLimits)
 {
-    NS_ABORT_MSG_IF(txopLimits.size() != m_links.size(),
+    if (txopLimits.empty())
+    {
+        // an empty vector is passed to use the default values specified by the standard
+        return;
+    }
+
+    NS_ABORT_MSG_IF(!m_links.empty() && txopLimits.size() != m_links.size(),
                     "The size of the given vector (" << txopLimits.size()
                                                      << ") does not match the number of links ("
                                                      << m_links.size() << ")");
+    m_userAccessParams.txopLimits = txopLimits;
+
     std::size_t i = 0;
     for (const auto& [id, link] : m_links)
     {
@@ -408,12 +499,21 @@
 void
 Txop::SetTxopLimit(Time txopLimit, uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << txopLimit << +linkId);
+    NS_LOG_FUNCTION(this << txopLimit << linkId);
+    NS_ASSERT_MSG(txopLimit.IsPositive(), "TXOP limit cannot be negative");
     NS_ASSERT_MSG((txopLimit.GetMicroSeconds() % 32 == 0),
                   "The TXOP limit must be expressed in multiple of 32 microseconds!");
+    NS_ASSERT_MSG(!m_links.empty(),
+                  "This function can only be called after that links have been created");
     GetLink(linkId).txopLimit = txopLimit;
 }
 
+const Txop::UserDefinedAccessParams&
+Txop::GetUserAccessParams() const
+{
+    return m_userAccessParams;
+}
+
 uint32_t
 Txop::GetMinCw() const
 {
@@ -515,7 +615,7 @@
 {
     m_queue->WipeAllExpiredMpdus();
     bool ret = static_cast<bool>(m_queue->Peek(linkId));
-    NS_LOG_FUNCTION(this << +linkId << ret);
+    NS_LOG_FUNCTION(this << linkId << ret);
     return ret;
 }
 
@@ -533,30 +633,61 @@
 Txop::Queue(Ptr<WifiMpdu> mpdu)
 {
     NS_LOG_FUNCTION(this << *mpdu);
-    const auto linkIds = m_mac->GetMacQueueScheduler()->GetLinkIds(m_queue->GetAc(), mpdu);
-    std::map<uint8_t, bool> hasFramesToTransmit;
+
+    // channel access can be requested on a blocked link, if the reason for blocking the link
+    // is temporary
+    auto linkIds = m_mac->GetMacQueueScheduler()->GetLinkIds(
+        m_queue->GetAc(),
+        mpdu,
+        {WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+         WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY});
+
+    // ignore the links for which a channel access request event is already running
+    for (auto it = linkIds.begin(); it != linkIds.end();)
+    {
+        if (const auto& event = GetLink(*it).accessRequest.event; event.IsPending())
+        {
+            it = linkIds.erase(it);
+        }
+        else
+        {
+            ++it;
+        }
+    }
 
     // save the status of the AC queues before enqueuing the MPDU (required to determine if
     // backoff is needed)
+    std::map<uint8_t, bool> hasFramesToTransmit;
     for (const auto linkId : linkIds)
     {
         hasFramesToTransmit[linkId] = HasFramesToTransmit(linkId);
     }
     m_queue->Enqueue(mpdu);
-    for (const auto linkId : linkIds)
+
+    // shuffle link IDs not to request channel access on links always in the same order
+    std::vector<uint8_t> shuffledLinkIds(linkIds.cbegin(), linkIds.cend());
+    Shuffle(shuffledLinkIds.begin(), shuffledLinkIds.end(), m_shuffleLinkIdsGen.GetRv());
+
+    if (!linkIds.empty() && g_log.IsEnabled(ns3::LOG_DEBUG))
+    {
+        std::stringstream ss;
+        std::copy(shuffledLinkIds.cbegin(),
+                  shuffledLinkIds.cend(),
+                  std::ostream_iterator<uint16_t>(ss, " "));
+        NS_LOG_DEBUG("Request channel access on link IDs: " << ss.str());
+    }
+
+    for (const auto linkId : shuffledLinkIds)
     {
         // schedule a call to StartAccessIfNeeded() to request channel access after that all the
         // packets of a burst have been enqueued, instead of requesting channel access right after
         // the first packet. The call to StartAccessIfNeeded() is scheduled only after the first
         // packet
-        if (auto& event = GetLink(linkId).accessRequest.event; !event.IsRunning())
-        {
-            event = Simulator::ScheduleNow(&Txop::StartAccessAfterEvent,
-                                           this,
-                                           linkId,
-                                           hasFramesToTransmit.at(linkId),
-                                           CHECK_MEDIUM_BUSY);
-        }
+        GetLink(linkId).accessRequest.event = Simulator::ScheduleNow(&Txop::StartAccessAfterEvent,
+                                                                     this,
+                                                                     linkId,
+                                                                     hasFramesToTransmit.at(linkId),
+                                                                     CHECK_MEDIUM_BUSY);
     }
 }
 
@@ -571,11 +702,23 @@
 void
 Txop::StartAccessAfterEvent(uint8_t linkId, bool hadFramesToTransmit, bool checkMediumBusy)
 {
-    NS_LOG_FUNCTION(this << +linkId << hadFramesToTransmit << checkMediumBusy);
+    NS_LOG_FUNCTION(this << linkId << hadFramesToTransmit << checkMediumBusy);
+
+    if (!m_mac->GetWifiPhy(linkId))
+    {
+        NS_LOG_DEBUG("No PHY operating on link " << +linkId);
+        return;
+    }
+
+    if (GetLink(linkId).access != NOT_REQUESTED)
+    {
+        NS_LOG_DEBUG("Channel access already requested or granted on link " << +linkId);
+        return;
+    }
 
-    if (GetLink(linkId).access != NOT_REQUESTED || !HasFramesToTransmit(linkId))
+    if (!HasFramesToTransmit(linkId))
     {
-        NS_LOG_DEBUG("No need to request channel access on link " << +linkId);
+        NS_LOG_DEBUG("No frames to transmit on link " << +linkId);
         return;
     }
 
@@ -609,21 +752,21 @@
 void
 Txop::NotifyAccessRequested(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +linkId);
+    NS_LOG_FUNCTION(this << linkId);
     GetLink(linkId).access = REQUESTED;
 }
 
 void
 Txop::NotifyChannelAccessed(uint8_t linkId, Time txopDuration)
 {
-    NS_LOG_FUNCTION(this << +linkId << txopDuration);
+    NS_LOG_FUNCTION(this << linkId << txopDuration);
     GetLink(linkId).access = GRANTED;
 }
 
 void
 Txop::NotifyChannelReleased(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +linkId);
+    NS_LOG_FUNCTION(this << linkId);
     GetLink(linkId).access = NOT_REQUESTED;
     GenerateBackoff(linkId);
     if (HasFramesToTransmit(linkId))
@@ -635,7 +778,7 @@
 void
 Txop::RequestAccess(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +linkId);
+    NS_LOG_FUNCTION(this << linkId);
     if (GetLink(linkId).access == NOT_REQUESTED)
     {
         m_mac->GetChannelAccessManager(linkId)->RequestAccess(this);
@@ -645,8 +788,8 @@
 void
 Txop::GenerateBackoff(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +linkId);
     uint32_t backoff = m_rng->GetInteger(0, GetCw(linkId));
+    NS_LOG_FUNCTION(this << linkId << backoff);
     m_backoffTrace(backoff, linkId);
     StartBackoffNow(backoff, linkId);
 }
@@ -654,7 +797,7 @@
 void
 Txop::NotifySleep(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +linkId);
+    NS_LOG_FUNCTION(this << linkId);
 }
 
 void
@@ -667,7 +810,7 @@
 void
 Txop::NotifyWakeUp(uint8_t linkId)
 {
-    NS_LOG_FUNCTION(this << +linkId);
+    NS_LOG_FUNCTION(this << linkId);
     // before wake up, no packet can be transmitted
     StartAccessAfterEvent(linkId, DIDNT_HAVE_FRAMES_TO_TRANSMIT, DONT_CHECK_MEDIUM_BUSY);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/txop.h ns-3.42/src/wifi/model/txop.h
--- ns-3.41/src/wifi/model/txop.h	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/txop.h	2024-05-29 15:29:47.208073900 -0700
@@ -25,11 +25,18 @@
 #include "ns3/nstime.h"
 #include "ns3/object.h"
 #include "ns3/traced-value.h"
+#include "ns3/uniform-random-bit-generator.h"
 
 #include <map>
 #include <memory>
 #include <vector>
 
+#define WIFI_TXOP_NS_LOG_APPEND_CONTEXT                                                            \
+    if (m_mac)                                                                                     \
+    {                                                                                              \
+        std::clog << "[mac=" << m_mac->GetAddress() << "] ";                                       \
+    }
+
 class EmlsrUlTxopTest;
 
 namespace ns3
@@ -44,6 +51,7 @@
 class UniformRandomVariable;
 class CtrlBAckResponseHeader;
 class WifiMac;
+enum AcIndex : uint8_t;           // opaque enum declaration
 enum WifiMacDropReason : uint8_t; // opaque enum declaration
 
 /**
@@ -74,14 +82,6 @@
 {
   public:
     Txop();
-
-    /**
-     * Constructor
-     *
-     * \param queue the wifi MAC queue
-     */
-    Txop(Ptr<WifiMacQueue> queue);
-
     ~Txop() override;
 
     /**
@@ -146,14 +146,16 @@
     void SetMinCw(uint32_t minCw);
     /**
      * Set the minimum contention window size for each link.
-     * Note that the size of <i>minCws</i> must match the number
+     * Note that an empty <i>minCws</i> is ignored, otherwise its size must match the number
      * of links.
      *
-     * \param minCws the minimum contention window size values.
+     * \param minCws the minimum contention window size for each link (links are sorted in
+     *               increasing order of link ID).
      */
-    void SetMinCws(std::vector<uint32_t> minCws);
+    void SetMinCws(const std::vector<uint32_t>& minCws);
     /**
-     * Set the minimum contention window size for the given link.
+     * Set the minimum contention window size for the given link. Note that this function can
+     * only be called after that links have been created.
      *
      * \param minCw the minimum contention window size.
      * \param linkId the ID of the given link
@@ -168,14 +170,16 @@
     void SetMaxCw(uint32_t maxCw);
     /**
      * Set the maximum contention window size for each link.
-     * Note that the size of <i>maxCws</i> must match the number
+     * Note that an empty <i>maxCws</i> is ignored, otherwise its size must match the number
      * of links.
      *
-     * \param maxCws the maximum contention window size values.
+     * \param maxCws the maximum contention window size for each link (links are sorted in
+     *               increasing order of link ID).
      */
-    void SetMaxCws(std::vector<uint32_t> maxCws);
+    void SetMaxCws(const std::vector<uint32_t>& maxCws);
     /**
-     * Set the maximum contention window size for the given link.
+     * Set the maximum contention window size for the given link. Note that this function can
+     * only be called after that links have been created.
      *
      * \param maxCw the maximum contention window size.
      * \param linkId the ID of the given link
@@ -190,14 +194,16 @@
     void SetAifsn(uint8_t aifsn);
     /**
      * Set the number of slots that make up an AIFS for each link.
-     * Note that the size of <i>aifsns</i> must match the number
+     * Note that an empty <i>aifsns</i> is ignored, otherwise its size must match the number
      * of links.
      *
-     * \param aifsns the number of slots that make up an AIFS for each link.
+     * \param aifsns the number of slots that make up an AIFS for each link (links are sorted in
+     *               increasing order of link ID).
      */
-    void SetAifsns(std::vector<uint8_t> aifsns);
+    void SetAifsns(const std::vector<uint8_t>& aifsns);
     /**
-     * Set the number of slots that make up an AIFS for the given link.
+     * Set the number of slots that make up an AIFS for the given link. Note that this function
+     * can only be called after that links have been created.
      *
      * \param aifsn the number of slots that make up an AIFS.
      * \param linkId the ID of the given link
@@ -212,17 +218,18 @@
     void SetTxopLimit(Time txopLimit);
     /**
      * Set the TXOP limit for each link.
-     * Note that the size of <i>txopLimits</i> must match the number
+     * Note that an empty <i>txopLimits</i> is ignored, otherwise its size must match the number
      * of links.
      *
-     * \param txopLimits the TXOP limit for each link.
+     * \param txopLimits the TXOP limit for each link (links are sorted in increasing order of
+     *                   link ID).
      */
     void SetTxopLimits(const std::vector<Time>& txopLimits);
     /**
-     * Set the TXOP limit for the given link.
+     * Set the TXOP limit for the given link. Note that this function can only be called after
+     * that links have been created.
      *
-     * \param txopLimit the TXOP limit.
-     *        Value zero corresponds to default Txop.
+     * \param txopLimit the TXOP limit (must not be negative)
      * \param linkId the ID of the given link
      */
     void SetTxopLimit(Time txopLimit, uint8_t linkId);
@@ -447,6 +454,25 @@
      */
     void SwapLinks(std::map<uint8_t, uint8_t> links);
 
+    /**
+     * DCF/EDCA access parameters for all the links provided by users via this class' attributes
+     * or the corresponding setter methods. For each access parameter, values are sorted in
+     * increasing order of link ID. If user provides access parameters, they are used by WifiMac
+     * instead of the default values specified by Table 9-155 of 802.11-2020.
+     */
+    struct UserDefinedAccessParams
+    {
+        std::vector<uint32_t> cwMins; //!< the minimum contention window values for all the links
+        std::vector<uint32_t> cwMaxs; //!< the maximum contention window values for all the links
+        std::vector<uint8_t> aifsns;  //!< the AIFSN values for all the links
+        std::vector<Time> txopLimits; //!< TXOP limit values for all the links
+    };
+
+    /**
+     * \return a const reference to user-provided access parameters
+     */
+    const UserDefinedAccessParams& GetUserAccessParams() const;
+
   protected:
     ///< ChannelAccessManager associated class
     friend class ChannelAccessManager;
@@ -455,6 +481,13 @@
     void DoDispose() override;
     void DoInitialize() override;
 
+    /**
+     * Create a wifi MAC queue containing packets of the given AC
+     *
+     * \param aci the index of the given AC
+     */
+    virtual void CreateQueue(AcIndex aci);
+
     /* Txop notifications forwarded here */
     /**
      * Notify that access request has been received for the given link.
@@ -549,11 +582,12 @@
      */
     const std::map<uint8_t, std::unique_ptr<LinkEntity>>& GetLinks() const;
 
-    DroppedMpdu m_droppedMpduCallback; //!< the dropped MPDU callback
-    Ptr<WifiMacQueue> m_queue;         //!< the wifi MAC queue
-    Ptr<MacTxMiddle> m_txMiddle;       //!< the MacTxMiddle
-    Ptr<WifiMac> m_mac;                //!< the wifi MAC
-    Ptr<UniformRandomVariable> m_rng;  //!< the random stream
+    DroppedMpdu m_droppedMpduCallback;             //!< the dropped MPDU callback
+    Ptr<WifiMacQueue> m_queue;                     //!< the wifi MAC queue
+    Ptr<MacTxMiddle> m_txMiddle;                   //!< the MacTxMiddle
+    Ptr<WifiMac> m_mac;                            //!< the wifi MAC
+    Ptr<UniformRandomVariable> m_rng;              //!< the random stream
+    UniformRandomBitGenerator m_shuffleLinkIdsGen; //!< random number generator to shuffle link IDs
 
     /// TracedCallback for backoff trace value typedef
     typedef TracedCallback<uint32_t /* value */, uint8_t /* linkId */> BackoffValueTracedCallback;
@@ -573,6 +607,8 @@
 
     std::map<uint8_t, std::unique_ptr<LinkEntity>>
         m_links; //!< ID-indexed map of LinkEntity objects
+
+    UserDefinedAccessParams m_userAccessParams; //!< user-defined DCF/EDCA access parameters
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/vht/vht-frame-exchange-manager.cc ns-3.42/src/wifi/model/vht/vht-frame-exchange-manager.cc
--- ns-3.41/src/wifi/model/vht/vht-frame-exchange-manager.cc	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/vht/vht-frame-exchange-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -23,7 +23,7 @@
 #include "ns3/log.h"
 
 #undef NS_LOG_APPEND_CONTEXT
-#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "][mac=" << m_self << "] "
+#define NS_LOG_APPEND_CONTEXT WIFI_FEM_NS_LOG_APPEND_CONTEXT
 
 namespace ns3
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/vht/vht-phy.cc ns-3.42/src/wifi/model/vht/vht-phy.cc
--- ns-3.41/src/wifi/model/vht/vht-phy.cc	2024-02-09 14:44:08.597795000 -0800
+++ ns-3.42/src/wifi/model/vht/vht-phy.cc	2024-05-29 15:29:47.208073900 -0700
@@ -31,6 +31,9 @@
 #include "ns3/wifi-psdu.h"
 #include "ns3/wifi-utils.h"
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
+
 namespace ns3
 {
 
@@ -583,8 +586,6 @@
 PhyEntity::CcaIndication
 VhtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
 {
-    NS_LOG_FUNCTION(this);
-
     if (m_wifiPhy->GetChannelWidth() < 80)
     {
         return HtPhy::GetCcaIndication(ppdu);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-acknowledgment.cc ns-3.42/src/wifi/model/wifi-acknowledgment.cc
--- ns-3.41/src/wifi/model/wifi-acknowledgment.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-acknowledgment.cc	2024-05-29 15:29:47.208073900 -0700
@@ -31,8 +31,7 @@
  */
 
 WifiAcknowledgment::WifiAcknowledgment(Method m)
-    : method(m),
-      acknowledgmentTime(Time::Min()) // uninitialized
+    : method(m)
 {
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-acknowledgment.h ns-3.42/src/wifi/model/wifi-acknowledgment.h
--- ns-3.41/src/wifi/model/wifi-acknowledgment.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-acknowledgment.h	2024-05-29 15:29:47.208073900 -0700
@@ -29,6 +29,7 @@
 
 #include <map>
 #include <memory>
+#include <optional>
 
 namespace ns3
 {
@@ -101,8 +102,8 @@
      */
     virtual void Print(std::ostream& os) const = 0;
 
-    const Method method;     //!< acknowledgment method
-    Time acknowledgmentTime; //!< time required by the acknowledgment method
+    const Method method;                    //!< acknowledgment method
+    std::optional<Time> acknowledgmentTime; //!< time required by the acknowledgment method
 
   private:
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-assoc-manager.cc ns-3.42/src/wifi/model/wifi-assoc-manager.cc
--- ns-3.41/src/wifi/model/wifi-assoc-manager.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-assoc-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -182,7 +182,7 @@
     for (auto ap = m_apList.begin(); ap != m_apList.end();)
     {
         if (!MatchScanParams(*ap) ||
-            (!m_allowedLinks.empty() && m_allowedLinks.count(ap->m_linkId) == 0))
+            (!m_allowedLinks.empty() && !m_allowedLinks.contains(ap->m_linkId)))
         {
             // remove AP info from list
             m_apListIt.erase(ap->m_bssid);
@@ -203,7 +203,7 @@
     NS_LOG_FUNCTION(this << apInfo);
 
     if (!CanBeInserted(apInfo) || !MatchScanParams(apInfo) ||
-        (!m_allowedLinks.empty() && m_allowedLinks.count(apInfo.m_linkId) == 0))
+        (!m_allowedLinks.empty() && !m_allowedLinks.contains(apInfo.m_linkId)))
     {
         return;
     }
@@ -314,7 +314,8 @@
         // mapping negotiation with the TID-To-Link Mapping Negotiation Support subfield of the
         // MLD Capabilities field of the Basic Multi-Link element it transmits to at least 1.
         // (Sec. 35.3.7.1.1 of 802.11be D3.1)
-        if (mldCapabilities->tidToLinkMappingSupport > 0 && negSupport.Get() == 0)
+        if (mldCapabilities->tidToLinkMappingSupport > 0 &&
+            negSupport.Get() == WifiTidToLinkMappingNegSupport::NOT_SUPPORTED)
         {
             NS_LOG_DEBUG("AP MLD supports TID-to-Link Mapping negotiation, while we don't");
             return false;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-default-ack-manager.cc ns-3.42/src/wifi/model/wifi-default-ack-manager.cc
--- ns-3.41/src/wifi/model/wifi-default-ack-manager.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-default-ack-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -111,13 +111,10 @@
     NS_ABORT_MSG_IF(maxDistFromStartingSeq >= SEQNO_SPACE_HALF_SIZE,
                     "The given QoS data frame is too old");
 
-    const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
+    const auto* psduInfo = txParams.GetPsduInfo(receiver);
 
-    if (!psduInfo || psduInfo->seqNumbers.find(tid) == psduInfo->seqNumbers.end())
-    {
-        // there are no aggregated MPDUs (so far)
-        return maxDistFromStartingSeq;
-    }
+    NS_ASSERT_MSG(psduInfo && psduInfo->seqNumbers.contains(tid),
+                  "There must be at least an MPDU with tid " << +tid);
 
     for (const auto& seqNumber : psduInfo->seqNumbers.at(tid))
     {
@@ -193,7 +190,7 @@
                         "While searching for given MPDU ("
                             << *mpdu << "), found first another one (" << *item
                             << ") with higher sequence number");
-        if (auto linkIds = item->GetInFlightLinkIds(); linkIds.count(m_linkId) > 0)
+        if (auto linkIds = item->GetInFlightLinkIds(); linkIds.contains(m_linkId))
         {
             NS_LOG_DEBUG("Found MPDU inflight on the same link");
             return true;
@@ -280,7 +277,8 @@
 
     if (receiver.IsGroup())
     {
-        NS_ABORT_MSG_IF(txParams.GetSize(receiver) > 0, "Unicast frames only can be aggregated");
+        NS_ABORT_MSG_IF(!txParams.LastAddedIsFirstMpdu(receiver),
+                        "Unicast frames only can be aggregated");
         auto acknowledgment = std::make_unique<WifiNoAck>();
         if (hdr.IsQosData())
         {
@@ -327,7 +325,8 @@
 
     // we get here if a response is needed
     uint8_t tid = GetTid(mpdu->GetPacket(), hdr);
-    if (!hdr.IsBlockAckReq() && txParams.GetSize(receiver) == 0 && !ExistInflightOnSameLink(mpdu))
+    if (!hdr.IsBlockAckReq() && txParams.LastAddedIsFirstMpdu(receiver) &&
+        !ExistInflightOnSameLink(mpdu))
     {
         NS_LOG_DEBUG("Sending a single MPDU, no previous frame to ack: request Normal Ack");
         auto acknowledgment = std::make_unique<WifiNormalAck>();
@@ -338,7 +337,7 @@
     }
 
     // we get here if multiple MPDUs are being/have been sent
-    if (!hdr.IsBlockAckReq() && (txParams.GetSize(receiver) == 0 || m_useExplicitBar))
+    if (!hdr.IsBlockAckReq() && (txParams.LastAddedIsFirstMpdu(receiver) || m_useExplicitBar))
     {
         // in case of single MPDU, there are previous unacknowledged frames, thus
         // we cannot use Implicit Block Ack Request policy, otherwise we get a
@@ -385,8 +384,6 @@
     const WifiMacHeader& hdr = mpdu->GetHeader();
     Mac48Address receiver = hdr.GetAddr1();
 
-    const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
-
     NS_ABORT_MSG_IF(!hdr.IsQosData(),
                     "QoS data frames only can be aggregated when transmitting a "
                     "DL MU PPDU acknowledged via a sequence of BAR and BA frames");
@@ -402,15 +399,13 @@
         acknowledgment = static_cast<WifiDlMuBarBaSequence*>(txParams.m_acknowledgment.get());
     }
 
-    if (psduInfo)
+    if (!txParams.LastAddedIsFirstMpdu(receiver))
     {
         // an MPDU addressed to the same receiver has been already added
         NS_ASSERT(acknowledgment);
 
-        if ((acknowledgment->stationsSendBlockAckReqTo.find(receiver) !=
-             acknowledgment->stationsSendBlockAckReqTo.end()) ||
-            (acknowledgment->stationsReplyingWithBlockAck.find(receiver) !=
-             acknowledgment->stationsReplyingWithBlockAck.end()))
+        if (acknowledgment->stationsSendBlockAckReqTo.contains(receiver) ||
+            acknowledgment->stationsReplyingWithBlockAck.contains(receiver))
         {
             // the receiver either is already listed among the stations that will
             // receive a BlockAckReq frame or is the station that will immediately
@@ -510,8 +505,6 @@
     const WifiMacHeader& hdr = mpdu->GetHeader();
     Mac48Address receiver = hdr.GetAddr1();
 
-    const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
-
     NS_ASSERT(!txParams.m_acknowledgment ||
               txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR);
 
@@ -521,7 +514,7 @@
         acknowledgment = static_cast<WifiDlMuTfMuBar*>(txParams.m_acknowledgment.get());
     }
 
-    if (!psduInfo)
+    if (txParams.LastAddedIsFirstMpdu(receiver))
     {
         // we get here if this is the first MPDU for this receiver.
         Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
@@ -600,8 +593,6 @@
     const WifiMacHeader& hdr = mpdu->GetHeader();
     Mac48Address receiver = hdr.GetAddr1();
 
-    const WifiTxParameters::PsduInfo* psduInfo = txParams.GetPsduInfo(receiver);
-
     NS_ASSERT(!txParams.m_acknowledgment ||
               txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF);
 
@@ -611,7 +602,7 @@
         acknowledgment = static_cast<WifiDlMuAggregateTf*>(txParams.m_acknowledgment.get());
     }
 
-    if (!psduInfo)
+    if (txParams.LastAddedIsFirstMpdu(receiver))
     {
         // we get here if this is the first MPDU for this receiver.
         Ptr<ApWifiMac> apMac = DynamicCast<ApWifiMac>(m_mac);
@@ -709,8 +700,9 @@
             }
             NS_ABORT_MSG_IF(aid12 == 0 || aid12 > 2007, "Allocation of RA-RUs is not supported");
 
-            NS_ASSERT(apMac->GetStaList(m_linkId).find(aid12) != apMac->GetStaList(m_linkId).end());
-            Mac48Address staAddress = apMac->GetStaList(m_linkId).find(aid12)->second;
+            const auto it = apMac->GetStaList(m_linkId).find(aid12);
+            NS_ASSERT(it != apMac->GetStaList(m_linkId).end());
+            const auto staAddress = it->second;
 
             // find a TID for which a BA agreement exists with the given originator
             uint8_t tid = 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-default-assoc-manager.cc ns-3.42/src/wifi/model/wifi-default-assoc-manager.cc
--- ns-3.41/src/wifi/model/wifi-default-assoc-manager.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-default-assoc-manager.cc	2024-05-29 15:29:47.208073900 -0700
@@ -240,7 +240,7 @@
     }
 
     if (std::none_of(m_channelSwitchInfo.begin(), m_channelSwitchInfo.end(), [](auto&& info) {
-            return info.timer.IsRunning();
+            return info.timer.IsPending();
         }))
     {
         // we are done
@@ -252,13 +252,13 @@
 WifiDefaultAssocManager::NotifyChannelSwitched(uint8_t linkId)
 {
     NS_LOG_FUNCTION(this << +linkId);
-    if (m_channelSwitchInfo.size() > linkId && m_channelSwitchInfo[linkId].timer.IsRunning())
+    if (m_channelSwitchInfo.size() > linkId && m_channelSwitchInfo[linkId].timer.IsPending())
     {
         // we were waiting for this notification
         m_channelSwitchInfo[linkId].timer.Cancel();
 
         if (std::none_of(m_channelSwitchInfo.begin(), m_channelSwitchInfo.end(), [](auto&& info) {
-                return info.timer.IsRunning();
+                return info.timer.IsPending();
             }))
         {
             // we are done
@@ -282,7 +282,7 @@
     setupLinks.erase(it);
 
     if (std::none_of(m_channelSwitchInfo.begin(), m_channelSwitchInfo.end(), [](auto&& info) {
-            return info.timer.IsRunning();
+            return info.timer.IsPending();
         }))
     {
         // we are done
@@ -293,7 +293,7 @@
 bool
 WifiDefaultAssocManager::CanBeInserted(const StaWifiMac::ApInfo& apInfo) const
 {
-    return (m_waitBeaconEvent.IsRunning() || m_probeRequestEvent.IsRunning());
+    return (m_waitBeaconEvent.IsPending() || m_probeRequestEvent.IsPending());
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-default-protection-manager.cc ns-3.42/src/wifi/model/wifi-default-protection-manager.cc
--- ns-3.41/src/wifi/model/wifi-default-protection-manager.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-default-protection-manager.cc	2024-05-29 15:29:47.212073800 -0700
@@ -51,6 +51,14 @@
                           "If enabled, always protect a DL/UL MU frame exchange with MU-RTS/CTS.",
                           BooleanValue(false),
                           MakeBooleanAccessor(&WifiDefaultProtectionManager::m_sendMuRts),
+                          MakeBooleanChecker())
+            .AddAttribute("SingleRtsPerTxop",
+                          "If enabled, a protection mechanism (RTS or MU-RTS) is normally used no "
+                          "more than once in a TXOP, regardless of the destination of the data "
+                          "frame (unless required for specific purposes, such as transmitting an "
+                          "Initial Control Frame to an EMLSR client).",
+                          BooleanValue(false),
+                          MakeBooleanAccessor(&WifiDefaultProtectionManager::m_singleRtsPerTxop),
                           MakeBooleanChecker());
     return tid;
 }
@@ -73,16 +81,10 @@
     // Call a separate method that handles MU-RTS/CTS protection in case of DL MU PPDU containing
     // more than one PSDU or in case the MPDU being added is addressed to an EMLSR client or in
     // case the protection method is already MU-RTS/CTS.
-    // A DL MU PPDU contains more than one PSDU if either the TX params' PSDU info map
-    // contains more than one entry or it contains one entry but the MPDU being added is
-    // addressed to a different receiver (hence generating a new entry if the MPDU is added)
     const auto& psduInfoMap = txParams.GetPsduInfoMap();
-    auto dlMuPpdu =
-        txParams.m_txVector.IsDlMu() &&
-        (psduInfoMap.size() > 1 ||
-         (psduInfoMap.size() == 1 && psduInfoMap.begin()->first != mpdu->GetHeader().GetAddr1()));
-    auto isEmlsrDestination =
-        GetWifiRemoteStationManager()->GetEmlsrEnabled(mpdu->GetHeader().GetAddr1());
+    auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
+    const auto& hdr = mpdu->GetHeader();
+    auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(hdr.GetAddr1());
 
     if (dlMuPpdu || isEmlsrDestination ||
         (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS))
@@ -102,7 +104,7 @@
     }
 
     // if this is a Trigger Frame, call a separate method
-    if (mpdu->GetHeader().IsTrigger())
+    if (hdr.IsTrigger())
     {
         return TryUlMuTransmission(mpdu, txParams);
     }
@@ -119,8 +121,7 @@
     NS_ASSERT(!txParams.m_protection || txParams.m_protection->method == WifiProtection::NONE);
 
     std::unique_ptr<WifiProtection> protection;
-    protection =
-        GetPsduProtection(mpdu->GetHeader(), txParams.GetSizeIfAddMpdu(mpdu), txParams.m_txVector);
+    protection = GetPsduProtection(hdr, txParams);
 
     // return the newly computed method if none was set or it is not NONE
     if (!txParams.m_protection || protection->method != WifiProtection::NONE)
@@ -157,9 +158,7 @@
     }
 
     std::unique_ptr<WifiProtection> protection;
-    protection = GetPsduProtection(msdu->GetHeader(),
-                                   txParams.GetSizeIfAggregateMsdu(msdu).second,
-                                   txParams.m_txVector);
+    protection = GetPsduProtection(msdu->GetHeader(), txParams);
 
     // the protection method may still be none
     if (protection->method == WifiProtection::NONE)
@@ -173,10 +172,9 @@
 
 std::unique_ptr<WifiProtection>
 WifiDefaultProtectionManager::GetPsduProtection(const WifiMacHeader& hdr,
-                                                uint32_t size,
-                                                const WifiTxVector& txVector) const
+                                                const WifiTxParameters& txParams) const
 {
-    NS_LOG_FUNCTION(this << hdr << size << txVector);
+    NS_LOG_FUNCTION(this << hdr << &txParams);
 
     // a non-initial fragment does not need to be protected, unless it is being retransmitted
     if (hdr.GetFragmentNumber() > 0 && !hdr.IsRetry())
@@ -184,8 +182,10 @@
         return std::make_unique<WifiNoProtection>();
     }
 
-    // no need to use protection if destination already received an RTS in this TXOP
-    if (m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas().count(hdr.GetAddr1()) == 1)
+    // no need to use protection if destination already received an RTS in this TXOP or
+    // SingleRtsPerTxop is true and a protection mechanism has been already used in this TXOP
+    if (const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
+        protectedStas.contains(hdr.GetAddr1()) || (m_singleRtsPerTxop && !protectedStas.empty()))
     {
         return std::make_unique<WifiNoProtection>();
     }
@@ -204,12 +204,12 @@
     }
 
     // check if RTS/CTS is needed
-    if (emlsrNeedRts || GetWifiRemoteStationManager()->NeedRts(hdr, size))
+    if (emlsrNeedRts || GetWifiRemoteStationManager()->NeedRts(hdr, txParams))
     {
         auto protection = std::make_unique<WifiRtsCtsProtection>();
         protection->rtsTxVector =
             GetWifiRemoteStationManager()->GetRtsTxVector(hdr.GetAddr1(),
-                                                          txVector.GetChannelWidth());
+                                                          txParams.m_txVector.GetChannelWidth());
         protection->ctsTxVector =
             GetWifiRemoteStationManager()->GetCtsTxVector(hdr.GetAddr1(),
                                                           protection->rtsTxVector.GetMode());
@@ -218,7 +218,7 @@
 
     // check if CTS-to-Self is needed
     if (GetWifiRemoteStationManager()->GetUseNonErpProtection() &&
-        GetWifiRemoteStationManager()->NeedCtsToSelf(txVector))
+        GetWifiRemoteStationManager()->NeedCtsToSelf(txParams.m_txVector))
     {
         auto protection = std::make_unique<WifiCtsToSelfProtection>();
         protection->ctsTxVector = GetWifiRemoteStationManager()->GetCtsToSelfTxVector();
@@ -236,19 +236,19 @@
 
     auto receiver = mpdu->GetHeader().GetAddr1();
     const auto& psduInfoMap = txParams.GetPsduInfoMap();
-    auto dlMuPpdu = txParams.m_txVector.IsDlMu() &&
-                    (psduInfoMap.size() > 1 ||
-                     (psduInfoMap.size() == 1 && psduInfoMap.begin()->first != receiver));
+    auto dlMuPpdu = txParams.m_txVector.IsDlMu() && psduInfoMap.size() > 1;
     auto isEmlsrDestination = GetWifiRemoteStationManager()->GetEmlsrEnabled(receiver);
     NS_ASSERT(
         dlMuPpdu || isEmlsrDestination ||
         (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS));
 
-    auto isProtected =
-        m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas().count(receiver) == 1;
+    const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
+    const auto isProtected = protectedStas.contains(receiver);
     bool needMuRts =
         (txParams.m_protection && txParams.m_protection->method == WifiProtection::MU_RTS_CTS) ||
-        (dlMuPpdu && m_sendMuRts && !isProtected) || (isEmlsrDestination && !isProtected);
+        (dlMuPpdu && m_sendMuRts && !isProtected &&
+         (!m_singleRtsPerTxop || protectedStas.empty())) ||
+        (isEmlsrDestination && !isProtected);
 
     if (!needMuRts)
     {
@@ -266,7 +266,7 @@
         protection = static_cast<WifiMuRtsCtsProtection*>(txParams.m_protection.get());
     }
 
-    if (txParams.GetPsduInfo(receiver) == nullptr)
+    if (txParams.LastAddedIsFirstMpdu(receiver))
     {
         // we get here if this is the first MPDU for this receiver.
         NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
@@ -281,6 +281,11 @@
             // txParams.m_protection points to an existing WifiMuRtsCtsProtection object.
             // We have to return a copy of this object including the needed changes
             protection = new WifiMuRtsCtsProtection(*protection);
+
+            // Add a User Info field for the new receiver
+            // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
+            // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
+            AddUserInfoToMuRts(protection->muRts, txWidth, receiver);
         }
         else
         {
@@ -298,7 +303,6 @@
             // Add a User Info field for each of the receivers already in the TX params
             for (const auto& [address, info] : txParams.GetPsduInfoMap())
             {
-                NS_ASSERT_MSG(address != receiver, "This must be the first MPDU for " << receiver);
                 AddUserInfoToMuRts(protection->muRts, txWidth, address);
             }
 
@@ -325,11 +329,6 @@
             GetWifiRemoteStationManager()->AdjustTxVectorForIcf(protection->muRtsTxVector);
         }
 
-        // Add a User Info field for the new receiver
-        // The UL HE-MCS, UL FEC Coding Type, UL DCM, SS Allocation and UL Target RSSI fields
-        // in the User Info field are reserved (Sec. 9.3.1.22.5 of 802.11ax)
-        AddUserInfoToMuRts(protection->muRts, txWidth, receiver);
-
         return std::unique_ptr<WifiMuRtsCtsProtection>(protection);
     }
 
@@ -364,6 +363,7 @@
     NS_ABORT_MSG_IF(m_mac->GetTypeOfStation() != AP, "HE APs only can send DL MU PPDUs");
     const auto& staList = StaticCast<ApWifiMac>(m_mac)->GetStaList(m_linkId);
 
+    const auto& protectedStas = m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas();
     bool allProtected = true;
     bool isUnprotectedEmlsrDst = false;
 
@@ -375,8 +375,7 @@
         auto staIt = staList.find(userInfo.GetAid12());
         NS_ASSERT(staIt != staList.cend());
         AddUserInfoToMuRts(protection->muRts, txWidth, staIt->second);
-        bool isProtected =
-            m_mac->GetFrameExchangeManager(m_linkId)->GetProtectedStas().count(staIt->second) == 1;
+        const auto isProtected = protectedStas.contains(staIt->second);
         allProtected = allProtected && isProtected;
 
         isUnprotectedEmlsrDst =
@@ -384,7 +383,9 @@
             (!isProtected && GetWifiRemoteStationManager()->GetEmlsrEnabled(staIt->second));
     }
 
-    bool needMuRts = (m_sendMuRts && !allProtected) || isUnprotectedEmlsrDst;
+    bool needMuRts =
+        (m_sendMuRts && !allProtected && (!m_singleRtsPerTxop || protectedStas.empty())) ||
+        isUnprotectedEmlsrDst;
 
     if (!needMuRts)
     {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-default-protection-manager.h ns-3.42/src/wifi/model/wifi-default-protection-manager.h
--- ns-3.41/src/wifi/model/wifi-default-protection-manager.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-default-protection-manager.h	2024-05-29 15:29:47.212073800 -0700
@@ -57,13 +57,12 @@
      * Select the protection method for a single PSDU.
      *
      * \param hdr the MAC header of the PSDU
-     * \param size the size in bytes of the PSDU
-     * \param txVector the TxVector used to transmit the PSDU
+     * \param txParams the TX parameters describing the PSDU
      * \return the selected protection method
      */
-    virtual std::unique_ptr<WifiProtection> GetPsduProtection(const WifiMacHeader& hdr,
-                                                              uint32_t size,
-                                                              const WifiTxVector& txVector) const;
+    virtual std::unique_ptr<WifiProtection> GetPsduProtection(
+        const WifiMacHeader& hdr,
+        const WifiTxParameters& txParams) const;
 
   private:
     /**
@@ -99,7 +98,8 @@
     virtual std::unique_ptr<WifiProtection> TryUlMuTransmission(Ptr<const WifiMpdu> mpdu,
                                                                 const WifiTxParameters& txParams);
 
-    bool m_sendMuRts; //!< true for sending an MU-RTS to protect DL MU PPDUs
+    bool m_sendMuRts;        //!< true for sending an MU-RTS to protect DL MU PPDUs
+    bool m_singleRtsPerTxop; //!< true for using protection only once in a TXOP
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-information-element.h ns-3.42/src/wifi/model/wifi-information-element.h
--- ns-3.41/src/wifi/model/wifi-information-element.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-information-element.h	2024-05-29 15:29:47.212073800 -0700
@@ -235,6 +235,8 @@
 
 #define IE_EXT_NON_INHERITANCE ((WifiInformationElementId)56)
 
+#define IE_EXT_HE_6GHZ_CAPABILITIES ((WifiInformationElementId)59)
+
 #define IE_EXT_EHT_OPERATION ((WifiInformationElementId)106)
 #define IE_EXT_MULTI_LINK_ELEMENT ((WifiInformationElementId)107)
 #define IE_EXT_EHT_CAPABILITIES ((WifiInformationElementId)108)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac.cc ns-3.42/src/wifi/model/wifi-mac.cc
--- ns-3.41/src/wifi/model/wifi-mac.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac.cc	2024-05-29 15:29:47.212073800 -0700
@@ -36,9 +36,14 @@
 #include "ns3/log.h"
 #include "ns3/packet.h"
 #include "ns3/pointer.h"
+#include "ns3/shuffle.h"
+#include "ns3/string.h"
 #include "ns3/vht-configuration.h"
 
 #include <algorithm>
+#include <cmath>
+#include <iterator>
+#include <sstream>
 
 namespace ns3
 {
@@ -97,28 +102,38 @@
                 MakeBooleanChecker())
             .AddAttribute("Txop",
                           "The Txop object.",
+                          TypeId::ATTR_GET |
+                              TypeId::ATTR_CONSTRUCT, // prevent setting after construction
                           PointerValue(),
-                          MakePointerAccessor(&WifiMac::GetTxop),
+                          MakePointerAccessor(&WifiMac::GetTxop, &WifiMac::SetTxop),
                           MakePointerChecker<Txop>())
             .AddAttribute("VO_Txop",
                           "Queue that manages packets belonging to AC_VO access class.",
+                          TypeId::ATTR_GET |
+                              TypeId::ATTR_CONSTRUCT, // prevent setting after construction
                           PointerValue(),
-                          MakePointerAccessor(&WifiMac::GetVOQueue),
+                          MakePointerAccessor(&WifiMac::GetVOQueue, &WifiMac::SetVoQueue),
                           MakePointerChecker<QosTxop>())
             .AddAttribute("VI_Txop",
                           "Queue that manages packets belonging to AC_VI access class.",
+                          TypeId::ATTR_GET |
+                              TypeId::ATTR_CONSTRUCT, // prevent setting after construction
                           PointerValue(),
-                          MakePointerAccessor(&WifiMac::GetVIQueue),
+                          MakePointerAccessor(&WifiMac::GetVIQueue, &WifiMac::SetViQueue),
                           MakePointerChecker<QosTxop>())
             .AddAttribute("BE_Txop",
                           "Queue that manages packets belonging to AC_BE access class.",
+                          TypeId::ATTR_GET |
+                              TypeId::ATTR_CONSTRUCT, // prevent setting after construction
                           PointerValue(),
-                          MakePointerAccessor(&WifiMac::GetBEQueue),
+                          MakePointerAccessor(&WifiMac::GetBEQueue, &WifiMac::SetBeQueue),
                           MakePointerChecker<QosTxop>())
             .AddAttribute("BK_Txop",
                           "Queue that manages packets belonging to AC_BK access class.",
+                          TypeId::ATTR_GET |
+                              TypeId::ATTR_CONSTRUCT, // prevent setting after construction
                           PointerValue(),
-                          MakePointerAccessor(&WifiMac::GetBKQueue),
+                          MakePointerAccessor(&WifiMac::GetBKQueue, &WifiMac::SetBkQueue),
                           MakePointerChecker<QosTxop>())
             .AddAttribute(
                 "MpduBufferSize",
@@ -345,6 +360,35 @@
     return tid;
 }
 
+int64_t
+WifiMac::AssignStreams(int64_t stream)
+{
+    NS_LOG_FUNCTION(this << stream);
+    if (GetNLinks() > 1)
+    {
+        m_shuffleLinkIdsGen.GetRv()->SetStream(stream);
+        return 1;
+    }
+    return 0;
+}
+
+void
+WifiMac::NotifyConstructionCompleted()
+{
+    NS_LOG_FUNCTION(this);
+
+    if (!m_qosSupported)
+    {
+        SetupDcfQueue();
+        return;
+    }
+
+    for (const auto& [aci, ac] : wifiAcList)
+    {
+        SetupEdcaQueue(aci);
+    }
+}
+
 void
 WifiMac::DoInitialize()
 {
@@ -428,7 +472,7 @@
 WifiMac::SetDevice(const Ptr<WifiNetDevice> device)
 {
     m_device = device;
-    if (GetHtSupported())
+    if (device->GetHtConfiguration())
     {
         // the configured BlockAck buffer size can now be capped
         m_mpduBufferSize = std::min(m_mpduBufferSize, GetMaxBaBufferSize());
@@ -489,12 +533,62 @@
     }
 }
 
+void
+WifiMac::SetTxop(Ptr<Txop> dcf)
+{
+    NS_LOG_FUNCTION(this << dcf);
+    if (!m_qosSupported)
+    {
+        m_txop = dcf;
+    }
+}
+
 Ptr<Txop>
 WifiMac::GetTxop() const
 {
     return m_txop;
 }
 
+void
+WifiMac::SetVoQueue(Ptr<QosTxop> edca)
+{
+    NS_LOG_FUNCTION(this << edca);
+    if (m_qosSupported)
+    {
+        m_edca.emplace(AC_VO, edca);
+    }
+}
+
+void
+WifiMac::SetViQueue(Ptr<QosTxop> edca)
+{
+    NS_LOG_FUNCTION(this << edca);
+    if (m_qosSupported)
+    {
+        m_edca.emplace(AC_VI, edca);
+    }
+}
+
+void
+WifiMac::SetBeQueue(Ptr<QosTxop> edca)
+{
+    NS_LOG_FUNCTION(this << edca);
+    if (m_qosSupported)
+    {
+        m_edca.emplace(AC_BE, edca);
+    }
+}
+
+void
+WifiMac::SetBkQueue(Ptr<QosTxop> edca)
+{
+    NS_LOG_FUNCTION(this << edca);
+    if (m_qosSupported)
+    {
+        m_edca.emplace(AC_BK, edca);
+    }
+}
+
 Ptr<QosTxop>
 WifiMac::GetQosTxop(AcIndex ac) const
 {
@@ -622,24 +716,31 @@
 }
 
 void
+WifiMac::SetupDcfQueue()
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT(m_txop);
+
+    m_txop->SetTxMiddle(m_txMiddle);
+    m_txop->SetDroppedMpduCallback(
+        MakeCallback(&DroppedMpduTracedCallback::operator(), &m_droppedMpduCallback));
+}
+
+void
 WifiMac::SetupEdcaQueue(AcIndex ac)
 {
     NS_LOG_FUNCTION(this << ac);
 
-    // Our caller shouldn't be attempting to setup a queue that is
-    // already configured.
-    NS_ASSERT(m_edca.find(ac) == m_edca.end());
-
-    Ptr<QosTxop> edca = CreateObject<QosTxop>(ac);
-    edca->SetTxMiddle(m_txMiddle);
-    edca->GetBaManager()->SetTxOkCallback(
+    auto edcaIt = m_edca.find(ac);
+    NS_ASSERT(edcaIt != m_edca.cend());
+
+    edcaIt->second->SetTxMiddle(m_txMiddle);
+    edcaIt->second->GetBaManager()->SetTxOkCallback(
         MakeCallback(&MpduTracedCallback::operator(), &m_ackedMpduCallback));
-    edca->GetBaManager()->SetTxFailedCallback(
+    edcaIt->second->GetBaManager()->SetTxFailedCallback(
         MakeCallback(&MpduTracedCallback::operator(), &m_nackedMpduCallback));
-    edca->SetDroppedMpduCallback(
+    edcaIt->second->SetDroppedMpduCallback(
         MakeCallback(&DroppedMpduTracedCallback::operator(), &m_droppedMpduCallback));
-
-    m_edca.insert(std::make_pair(ac, edca));
 }
 
 void
@@ -725,31 +826,48 @@
         break;
     }
 
-    std::vector<uint32_t> cwValues(m_links.size());
-    std::vector<uint8_t> aifsnValues(m_links.size());
-    std::vector<Time> txopLimitValues(m_links.size());
-
-    std::fill(cwValues.begin(), cwValues.end(), cwMinValue);
-    dcf->SetMinCws(cwValues);
-    std::fill(cwValues.begin(), cwValues.end(), cwMaxValue);
-    dcf->SetMaxCws(cwValues);
-    std::fill(aifsnValues.begin(), aifsnValues.end(), aifsnValue);
-    dcf->SetAifsns(aifsnValues);
-    std::transform(isDsss.begin(),
-                   isDsss.end(),
-                   txopLimitValues.begin(),
-                   [&txopLimitDsss, &txopLimitNoDsss](bool dsss) {
-                       return (dsss ? txopLimitDsss : txopLimitNoDsss);
-                   });
-    dcf->SetTxopLimits(txopLimitValues);
+    const auto& userDefinedParams = dcf->GetUserAccessParams();
+
+    dcf->SetMinCws(!userDefinedParams.cwMins.empty()
+                       ? userDefinedParams.cwMins
+                       : std::vector<uint32_t>(m_links.size(), cwMinValue));
+    dcf->SetMaxCws(!userDefinedParams.cwMaxs.empty()
+                       ? userDefinedParams.cwMaxs
+                       : std::vector<uint32_t>(m_links.size(), cwMaxValue));
+    dcf->SetAifsns(!userDefinedParams.aifsns.empty()
+                       ? userDefinedParams.aifsns
+                       : std::vector<uint8_t>(m_links.size(), aifsnValue));
+
+    if (!userDefinedParams.txopLimits.empty())
+    {
+        dcf->SetTxopLimits(userDefinedParams.txopLimits);
+    }
+    else
+    {
+        std::vector<Time> txopLimitValues(m_links.size());
+        std::transform(isDsss.begin(),
+                       isDsss.end(),
+                       txopLimitValues.begin(),
+                       [&txopLimitDsss, &txopLimitNoDsss](bool dsss) {
+                           return (dsss ? txopLimitDsss : txopLimitNoDsss);
+                       });
+        dcf->SetTxopLimits(txopLimitValues);
+    }
 }
 
 void
-WifiMac::ConfigureStandard(WifiStandard standard)
-{
-    NS_LOG_FUNCTION(this << standard);
-    NS_ABORT_IF(standard >= WIFI_STANDARD_80211n && !m_qosSupported);
-    NS_ABORT_MSG_IF(m_links.empty(), "No PHY configured yet");
+WifiMac::CompleteConfig()
+{
+    NS_ASSERT_MSG(!m_links.empty(), "CompleteConfig cannot be called before creating links");
+
+    const auto& link = *m_links.cbegin()->second;
+
+    if (!link.phy || !link.stationManager || !link.channelAccessManager || !link.feManager)
+    {
+        return;
+    }
+
+    NS_LOG_FUNCTION(this);
 
     for (auto& [id, link] : m_links)
     {
@@ -758,23 +876,18 @@
             "[LinkID " << +id
                        << "] PHY must have been set and an operating channel must have been set");
 
-        // do not create a ChannelAccessManager and a FrameExchangeManager if they
-        // already exist (this function may be called after ResetWifiPhys)
-        if (!link->channelAccessManager)
-        {
-            link->channelAccessManager = CreateObject<ChannelAccessManager>();
-        }
+        NS_ABORT_MSG_IF(!link->channelAccessManager,
+                        "[LinkID " << +id << "] A channel access manager must have been set");
+
+        NS_ABORT_MSG_IF(!link->feManager,
+                        "[LinkID " << +id << "] A frame exchange manager must have been set");
+
         link->channelAccessManager->SetupPhyListener(link->phy);
+        link->channelAccessManager->SetupFrameExchangeManager(link->feManager);
 
-        if (!link->feManager)
-        {
-            link->feManager = SetupFrameExchangeManager(standard);
-        }
         link->feManager->SetWifiPhy(link->phy);
-        link->feManager->SetWifiMac(this);
-        link->feManager->SetLinkId(id);
-        link->channelAccessManager->SetLinkId(id);
-        link->channelAccessManager->SetupFrameExchangeManager(link->feManager);
+        link->feManager->SetMacTxMiddle(m_txMiddle);
+        link->feManager->SetMacRxMiddle(m_rxMiddle);
 
         if (m_txop)
         {
@@ -789,6 +902,8 @@
 
         ConfigurePhyDependentParameters(id);
     }
+
+    DoCompleteConfig();
 }
 
 void
@@ -809,55 +924,57 @@
     ConfigureContentionWindow(cwmin, cwmax);
 }
 
-Ptr<FrameExchangeManager>
-WifiMac::SetupFrameExchangeManager(WifiStandard standard)
+bool
+WifiMac::CreateLinksIfNeeded(std::size_t nLinks)
 {
-    NS_LOG_FUNCTION(this << standard);
-    NS_ABORT_MSG_IF(standard == WIFI_STANDARD_UNSPECIFIED, "Wifi standard not set");
-    Ptr<FrameExchangeManager> feManager;
-
-    if (standard >= WIFI_STANDARD_80211be)
-    {
-        feManager = CreateObject<EhtFrameExchangeManager>();
-    }
-    else if (standard >= WIFI_STANDARD_80211ax)
+    if (!m_links.empty())
     {
-        feManager = CreateObject<HeFrameExchangeManager>();
+        return false;
     }
-    else if (standard >= WIFI_STANDARD_80211ac)
-    {
-        feManager = CreateObject<VhtFrameExchangeManager>();
-    }
-    else if (standard >= WIFI_STANDARD_80211n)
+
+    for (std::size_t i = 0; i < nLinks; i++)
     {
-        feManager = CreateObject<HtFrameExchangeManager>();
+        m_links.emplace(i, CreateLinkEntity());
+        m_linkIds.insert(i);
     }
-    else if (m_qosSupported)
+    return true;
+}
+
+void
+WifiMac::SetFrameExchangeManagers(const std::vector<Ptr<FrameExchangeManager>>& feManagers)
+{
+    NS_LOG_FUNCTION(this);
+
+    if (!CreateLinksIfNeeded(feManagers.size()))
     {
-        feManager = CreateObject<QosFrameExchangeManager>();
+        NS_ABORT_MSG_IF(feManagers.size() != m_links.size(),
+                        "The number of provided Frame Exchange Manager objects ("
+                            << feManagers.size() << ") must match the number of existing links ("
+                            << m_links.size() << ")");
     }
-    else
+
+    for (auto managerIt = feManagers.cbegin(); auto& [id, link] : m_links)
     {
-        feManager = CreateObject<FrameExchangeManager>();
+        link->feManager = *managerIt++;
+        link->feManager->SetWifiMac(this);
+        link->feManager->SetLinkId(id);
+        // connect callbacks
+        link->feManager->GetWifiTxTimer().SetMpduResponseTimeoutCallback(
+            MakeCallback(&MpduResponseTimeoutTracedCallback::operator(),
+                         &m_mpduResponseTimeoutCallback));
+        link->feManager->GetWifiTxTimer().SetPsduResponseTimeoutCallback(
+            MakeCallback(&PsduResponseTimeoutTracedCallback::operator(),
+                         &m_psduResponseTimeoutCallback));
+        link->feManager->GetWifiTxTimer().SetPsduMapResponseTimeoutCallback(
+            MakeCallback(&PsduMapResponseTimeoutTracedCallback::operator(),
+                         &m_psduMapResponseTimeoutCallback));
+        link->feManager->SetDroppedMpduCallback(
+            MakeCallback(&DroppedMpduTracedCallback::operator(), &m_droppedMpduCallback));
+        link->feManager->SetAckedMpduCallback(
+            MakeCallback(&MpduTracedCallback::operator(), &m_ackedMpduCallback));
     }
 
-    feManager->SetMacTxMiddle(m_txMiddle);
-    feManager->SetMacRxMiddle(m_rxMiddle);
-    feManager->SetAddress(GetAddress());
-    feManager->GetWifiTxTimer().SetMpduResponseTimeoutCallback(
-        MakeCallback(&MpduResponseTimeoutTracedCallback::operator(),
-                     &m_mpduResponseTimeoutCallback));
-    feManager->GetWifiTxTimer().SetPsduResponseTimeoutCallback(
-        MakeCallback(&PsduResponseTimeoutTracedCallback::operator(),
-                     &m_psduResponseTimeoutCallback));
-    feManager->GetWifiTxTimer().SetPsduMapResponseTimeoutCallback(
-        MakeCallback(&PsduMapResponseTimeoutTracedCallback::operator(),
-                     &m_psduMapResponseTimeoutCallback));
-    feManager->SetDroppedMpduCallback(
-        MakeCallback(&DroppedMpduTracedCallback::operator(), &m_droppedMpduCallback));
-    feManager->SetAckedMpduCallback(
-        MakeCallback(&MpduTracedCallback::operator(), &m_ackedMpduCallback));
-    return feManager;
+    CompleteConfig();
 }
 
 Ptr<FrameExchangeManager>
@@ -866,6 +983,28 @@
     return GetLink(linkId).feManager;
 }
 
+void
+WifiMac::SetChannelAccessManagers(const std::vector<Ptr<ChannelAccessManager>>& caManagers)
+{
+    NS_LOG_FUNCTION(this);
+
+    if (!CreateLinksIfNeeded(caManagers.size()))
+    {
+        NS_ABORT_MSG_IF(caManagers.size() != m_links.size(),
+                        "The number of provided Channel Access Manager objects ("
+                            << caManagers.size() << ") must match the number of existing links ("
+                            << m_links.size() << ")");
+    }
+
+    for (auto managerIt = caManagers.cbegin(); auto& [id, link] : m_links)
+    {
+        link->channelAccessManager = *managerIt++;
+        link->channelAccessManager->SetLinkId(id);
+    }
+
+    CompleteConfig();
+}
+
 Ptr<ChannelAccessManager>
 WifiMac::GetChannelAccessManager(uint8_t linkId) const
 {
@@ -885,21 +1024,21 @@
 {
     NS_LOG_FUNCTION(this);
 
-    NS_ABORT_MSG_UNLESS(m_links.empty() || m_links.size() == stationManagers.size(),
-                        "If links have been already created, the number of provided "
-                        "Remote Manager objects ("
+    if (!CreateLinksIfNeeded(stationManagers.size()))
+    {
+        NS_ABORT_MSG_IF(stationManagers.size() != m_links.size(),
+                        "The number of provided Remote Manager objects ("
                             << stationManagers.size()
-                            << ") must "
-                               "match the number of links ("
-                            << m_links.size() << ")");
+                            << ") must match the number of existing links (" << m_links.size()
+                            << ")");
+    }
 
-    for (std::size_t i = 0; i < stationManagers.size(); i++)
+    for (auto managerIt = stationManagers.cbegin(); auto& [id, link] : m_links)
     {
-        // the link may already exist in case PHY objects were configured first
-        auto [it, inserted] = m_links.emplace(i, CreateLinkEntity());
-        m_linkIds.insert(i);
-        it->second->stationManager = stationManagers[i];
+        link->stationManager = *managerIt++;
     }
+
+    CompleteConfig();
 }
 
 Ptr<WifiRemoteStationManager>
@@ -1011,7 +1150,7 @@
         }
 
         std::unique_ptr<LinkEntity> linkToMove;
-        NS_ASSERT(m_links.find(from) != m_links.cend());
+        NS_ASSERT(m_links.contains(from));
         linkToMove.swap(m_links.at(from)); // from is now out of m_links
         auto empty = from;                 // track empty cell in m_links
 
@@ -1062,6 +1201,14 @@
     }
 }
 
+bool
+WifiMac::Is6GhzBand(uint8_t linkId) const
+{
+    auto phy = GetLink(linkId).phy;
+    NS_ASSERT(phy);
+    return phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ;
+}
+
 void
 WifiMac::UpdateTidToLinkMapping(const Mac48Address& mldAddr,
                                 WifiDirection dir,
@@ -1148,23 +1295,20 @@
     NS_LOG_FUNCTION(this);
     ResetWifiPhys();
 
-    NS_ABORT_MSG_UNLESS(m_links.empty() || m_links.size() == phys.size(),
-                        "If links have been already created, the number of provided "
-                        "PHY objects ("
-                            << phys.size()
-                            << ") must match the number "
-                               "of links ("
+    if (!CreateLinksIfNeeded(phys.size()))
+    {
+        NS_ABORT_MSG_IF(phys.size() != m_links.size(),
+                        "The number of provided PHY objects ("
+                            << phys.size() << ") must match the number of existing links ("
                             << m_links.size() << ")");
+    }
 
-    for (std::size_t i = 0; i < phys.size(); i++)
+    for (auto phyIt = phys.cbegin(); auto& [id, link] : m_links)
     {
-        // the link may already exist in case we are setting new PHY objects
-        // (ResetWifiPhys just nullified the PHY(s) but left the links)
-        // or the remote station managers were configured first
-        auto [it, inserted] = m_links.emplace(i, CreateLinkEntity());
-        m_linkIds.insert(i);
-        it->second->phy = phys[i];
+        link->phy = *phyIt++;
     }
+
+    CompleteConfig();
 }
 
 Ptr<WifiPhy>
@@ -1197,25 +1341,6 @@
     NS_LOG_FUNCTION(this << enable);
     NS_ABORT_IF(IsInitialized());
     m_qosSupported = enable;
-
-    if (!m_qosSupported)
-    {
-        // create a non-QoS TXOP
-        m_txop = CreateObject<Txop>();
-        m_txop->SetTxMiddle(m_txMiddle);
-        m_txop->SetDroppedMpduCallback(
-            MakeCallback(&DroppedMpduTracedCallback::operator(), &m_droppedMpduCallback));
-    }
-    else
-    {
-        // Construct the EDCAFs. The ordering is important - highest
-        // priority (Table 9-1 UP-to-AC mapping; IEEE 802.11-2012) must be created
-        // first.
-        SetupEdcaQueue(AC_VO);
-        SetupEdcaQueue(AC_VI);
-        SetupEdcaQueue(AC_BE);
-        SetupEdcaQueue(AC_BK);
-    }
 }
 
 bool
@@ -1388,7 +1513,12 @@
                                const Mac48Address& address,
                                const std::set<uint8_t>& linkIds)
 {
-    NS_LOG_FUNCTION(this << reason << address);
+    std::stringstream ss;
+    if (g_log.IsEnabled(ns3::LOG_FUNCTION))
+    {
+        std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+    }
+    NS_LOG_FUNCTION(this << reason << address << ss.str());
     NS_ASSERT(m_scheduler);
 
     for (const auto linkId : linkIds)
@@ -1429,10 +1559,22 @@
                                  const Mac48Address& address,
                                  const std::set<uint8_t>& linkIds)
 {
-    NS_LOG_FUNCTION(this << reason << address);
     NS_ASSERT(m_scheduler);
 
-    for (const auto linkId : linkIds)
+    // shuffle link IDs not to unblock links always in the same order
+    std::vector<uint8_t> shuffledLinkIds(linkIds.cbegin(), linkIds.cend());
+    Shuffle(shuffledLinkIds.begin(), shuffledLinkIds.end(), m_shuffleLinkIdsGen.GetRv());
+
+    std::stringstream ss;
+    if (g_log.IsEnabled(ns3::LOG_FUNCTION))
+    {
+        std::copy(shuffledLinkIds.cbegin(),
+                  shuffledLinkIds.cend(),
+                  std::ostream_iterator<uint16_t>(ss, " "));
+    }
+    NS_LOG_FUNCTION(this << reason << address << ss.str());
+
+    for (const auto linkId : shuffledLinkIds)
     {
         auto& link = GetLink(linkId);
         auto linkAddr = link.stationManager->GetAffiliatedStaAddress(address).value_or(address);
@@ -1758,16 +1900,18 @@
 }
 
 bool
-WifiMac::GetHtSupported() const
+WifiMac::GetHtSupported(uint8_t linkId) const
 {
-    return bool(GetDevice()->GetHtConfiguration());
+    return (GetDevice()->GetHtConfiguration() &&
+            GetWifiPhy(linkId)->GetPhyBand() != WIFI_PHY_BAND_6GHZ);
 }
 
 bool
 WifiMac::GetVhtSupported(uint8_t linkId) const
 {
     return (GetDevice()->GetVhtConfiguration() &&
-            GetWifiPhy(linkId)->GetPhyBand() != WIFI_PHY_BAND_2_4GHZ);
+            GetWifiPhy(linkId)->GetPhyBand() != WIFI_PHY_BAND_2_4GHZ &&
+            GetWifiPhy(linkId)->GetPhyBand() != WIFI_PHY_BAND_6GHZ);
 }
 
 bool
@@ -1845,7 +1989,7 @@
     {
         return 256;
     }
-    NS_ASSERT(address ? GetHtSupported(*address) : GetHtSupported());
+    NS_ASSERT(address ? GetHtSupported(*address) : static_cast<bool>(GetHtConfiguration()));
     return 64;
 }
 
@@ -1949,7 +2093,7 @@
 {
     NS_LOG_FUNCTION(this);
     ExtendedCapabilities capabilities;
-    capabilities.SetHtSupported(GetHtSupported());
+    capabilities.SetHtSupported(GetHtSupported(SINGLE_LINK_OP_ID));
     capabilities.SetVhtSupported(GetVhtSupported(SINGLE_LINK_OP_ID));
     // TODO: to be completed
     return capabilities;
@@ -1959,7 +2103,7 @@
 WifiMac::GetHtCapabilities(uint8_t linkId) const
 {
     NS_LOG_FUNCTION(this << +linkId);
-    NS_ASSERT(GetHtSupported());
+    NS_ASSERT(GetHtSupported(linkId));
     HtCapabilities capabilities;
 
     auto phy = GetWifiPhy(linkId);
@@ -2153,6 +2297,41 @@
 
     return capabilities;
 }
+
+He6GhzBandCapabilities
+WifiMac::GetHe6GhzBandCapabilities(uint8_t linkId) const
+{
+    auto phy = GetLink(linkId).phy;
+    NS_ASSERT_MSG(phy->GetPhyBand() == WIFI_PHY_BAND_6GHZ,
+                  "Getting HE 6 GHz band capabilities on band different than 6 GHz");
+
+    He6GhzBandCapabilities capabilities;
+
+    // Set Maximum MPDU Length subfield
+    const auto maxAmsduSize =
+        std::max({m_voMaxAmsduSize, m_viMaxAmsduSize, m_beMaxAmsduSize, m_bkMaxAmsduSize});
+    if (maxAmsduSize <= 3839)
+    {
+        capabilities.SetMaxMpduLength(3895);
+    }
+    else if (maxAmsduSize <= 7935)
+    {
+        capabilities.SetMaxMpduLength(7991);
+    }
+    else
+    {
+        capabilities.SetMaxMpduLength(11454);
+    }
+
+    auto maxAmpduLength =
+        std::max({m_voMaxAmpduSize, m_viMaxAmpduSize, m_beMaxAmpduSize, m_bkMaxAmpduSize});
+    // round to the next power of two minus one
+    maxAmpduLength = (1UL << static_cast<uint32_t>(std::ceil(std::log2(maxAmpduLength + 1)))) - 1;
+    // The maximum A-MPDU length in HE 6 GHz Band Capabilities elements ranges from 2^13-1 to 2^20-1
+    capabilities.SetMaxAmpduLength(std::min(std::max(maxAmpduLength, 8191U), 1048575U));
+
+    return capabilities;
+}
 
 EhtCapabilities
 WifiMac::GetEhtCapabilities(uint8_t linkId) const
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac.h ns-3.42/src/wifi/model/wifi-mac.h
--- ns-3.41/src/wifi/model/wifi-mac.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac.h	2024-05-29 15:29:47.212073800 -0700
@@ -26,6 +26,8 @@
 #include "wifi-remote-station-manager.h"
 #include "wifi-standards.h"
 
+#include "ns3/uniform-random-bit-generator.h"
+
 #include <functional>
 #include <list>
 #include <map>
@@ -55,6 +57,7 @@
 class ExtendedCapabilities;
 class OriginatorBlockAckAgreement;
 class RecipientBlockAckAgreement;
+class UniformRandomVariable;
 
 /**
  * \ingroup wifi
@@ -109,6 +112,17 @@
     WifiMac& operator=(const WifiMac&) = delete;
 
     /**
+     * Assign a fixed random variable stream number to the random variables
+     * used by this model.  Return the number of streams (possibly zero) that
+     * have been assigned.
+     *
+     * \param stream first stream index to use
+     *
+     * \return the number of stream indices assigned by this model
+     */
+    virtual int64_t AssignStreams(int64_t stream);
+
+    /**
      * Sets the device this PHY is associated with.
      *
      * \param device the device this PHY is associated with
@@ -130,6 +144,11 @@
     Ptr<FrameExchangeManager> GetFrameExchangeManager(uint8_t linkId = SINGLE_LINK_OP_ID) const;
 
     /**
+     * \param feManagers the frame exchange managers attached to this MAC.
+     */
+    void SetFrameExchangeManagers(const std::vector<Ptr<FrameExchangeManager>>& feManagers);
+
+    /**
      * Get the Channel Access Manager associated with the given link
      *
      * \param linkId the ID of the given link
@@ -138,6 +157,11 @@
     Ptr<ChannelAccessManager> GetChannelAccessManager(uint8_t linkId = SINGLE_LINK_OP_ID) const;
 
     /**
+     * \param caManagers the channel access managers attached to this MAC.
+     */
+    void SetChannelAccessManagers(const std::vector<Ptr<ChannelAccessManager>>& caManagers);
+
+    /**
      * Get the number of links (can be greater than 1 for 11be devices only).
      *
      * \return the number of links used by this MAC
@@ -174,6 +198,14 @@
     std::optional<uint8_t> GetLinkForPhy(std::size_t phyId) const;
 
     /**
+     * Indicate if a given link is on the 6 GHz band.
+     *
+     * \param linkId the ID of the given link
+     * \return whether the given link is on the 6 GHz band
+     */
+    bool Is6GhzBand(uint8_t linkId) const;
+
+    /**
      * \param remoteAddr the (MLD or link) address of a remote device
      * \return the MLD address of the remote device having the given (MLD or link) address, if
      *         the remote device is an MLD.
@@ -468,16 +500,6 @@
     void NotifyRxDrop(Ptr<const Packet> packet);
 
     /**
-     * \param standard the wifi standard to be configured
-     *
-     * This method completes the configuration process for a requested PHY standard
-     * by creating the Frame Exchange Manager and the Channel Access Manager and
-     * configuring the PHY dependent parameters.
-     * This method can only be called after a configured PHY has been set.
-     */
-    virtual void ConfigureStandard(WifiStandard standard);
-
-    /**
      * \return pointer to HtConfiguration if it exists
      */
     Ptr<HtConfiguration> GetHtConfiguration() const;
@@ -522,6 +544,13 @@
      */
     HeCapabilities GetHeCapabilities(uint8_t linkId) const;
     /**
+     * Return the HE 6GHz band capabilities of the device for the given 6 GHz link.
+     *
+     * \param linkId the ID of the given 6 GHz link
+     * \return the HE 6GHz band capabilities that we support
+     */
+    He6GhzBandCapabilities GetHe6GhzBandCapabilities(uint8_t linkId) const;
+    /**
      * Return the EHT capabilities of the device for the given link.
      *
      * \param linkId the ID of the given link
@@ -550,11 +579,12 @@
      */
     bool GetDsssSupported(uint8_t linkId) const;
     /**
-     * Return whether the device supports HT.
+     * Return whether the device supports HT on the given link.
      *
+     * \param linkId the ID of the given link.
      * \return true if HT is supported, false otherwise
      */
-    bool GetHtSupported() const;
+    bool GetHtSupported(uint8_t linkId) const;
     /**
      * Return whether the device supports VHT on the given link.
      *
@@ -730,6 +760,7 @@
   protected:
     void DoInitialize() override;
     void DoDispose() override;
+    void NotifyConstructionCompleted() override;
 
     /**
      * \param cwMin the minimum contention window size
@@ -741,15 +772,6 @@
     virtual void ConfigureContentionWindow(uint32_t cwMin, uint32_t cwMax);
 
     /**
-     * Enable or disable QoS support for the device. Construct a Txop object
-     * or QosTxop objects accordingly. This method can only be called before
-     * initialization.
-     *
-     * \param enable whether QoS is supported
-     */
-    void SetQosSupported(bool enable);
-
-    /**
      * Enable or disable short slot time feature.
      *
      * \param enable true if short slot time is to be supported,
@@ -899,6 +921,16 @@
 
   private:
     /**
+     * Complete the configuration of the MAC layer components.
+     */
+    void CompleteConfig();
+
+    /**
+     * Allow subclasses to complete the configuration of the MAC layer components.
+     */
+    virtual void DoCompleteConfig() = 0;
+
+    /**
      * \param dcf the DCF to be configured
      * \param cwmin the minimum contention window for the DCF
      * \param cwmax the maximum contention window for the DCF
@@ -921,6 +953,60 @@
     void ConfigurePhyDependentParameters(uint8_t linkId);
 
     /**
+     * Enable or disable QoS support for the device. Construct a Txop object or QosTxop objects
+     * accordingly. This method is private so that it is only used while constructing this object.
+     *
+     * \param enable whether QoS is supported
+     */
+    void SetQosSupported(bool enable);
+
+    /**
+     * Set the Txop object.
+     * This method is private so that it is only used while constructing this object.
+     *
+     * \param dcf the Txop object
+     */
+    void SetTxop(Ptr<Txop> dcf);
+
+    /**
+     * Set the AC_VO channel access function
+     * This method is private so that it is only used while constructing this object.
+     *
+     * \param edca the QosTxop object for AC_VO
+     */
+    void SetVoQueue(Ptr<QosTxop> edca);
+
+    /**
+     * Set the AC_VI channel access function
+     * This method is private so that it is only used while constructing this object.
+     *
+     * \param edca the QosTxop object for AC_VI
+     */
+    void SetViQueue(Ptr<QosTxop> edca);
+
+    /**
+     * Set the AC_BE channel access function
+     * This method is private so that it is only used while constructing this object.
+     *
+     * \param edca the QosTxop object for AC_BE
+     */
+    void SetBeQueue(Ptr<QosTxop> edca);
+
+    /**
+     * Set the AC_BK channel access function
+     * This method is private so that it is only used while constructing this object.
+     *
+     * \param edca the QosTxop object for AC_BK
+     */
+    void SetBkQueue(Ptr<QosTxop> edca);
+
+    /**
+     * This method is a private utility invoked to configure the channel
+     * access function for devices that do not support QoS.
+     */
+    void SetupDcfQueue();
+
+    /**
      * This method is a private utility invoked to configure the channel
      * access function for the specified Access Category.
      *
@@ -929,13 +1015,12 @@
     void SetupEdcaQueue(AcIndex ac);
 
     /**
-     * Create a Frame Exchange Manager depending on the supported version
-     * of the standard.
+     * If no link has been already created, create the given number links; otherwise, do nothing.
      *
-     * \param standard the supported version of the standard
-     * \return the created Frame Exchange Manager
+     * \param nLinks the given number of links
+     * \return whether the given number of links have been created
      */
-    Ptr<FrameExchangeManager> SetupFrameExchangeManager(WifiStandard standard);
+    bool CreateLinksIfNeeded(std::size_t nLinks);
 
     /**
      * Create a LinkEntity object.
@@ -1077,6 +1162,8 @@
 
     uint16_t m_mpduBufferSize; //!< BlockAck buffer size (in number of MPDUs)
 
+    UniformRandomBitGenerator m_shuffleLinkIdsGen; //!< random number generator to shuffle link IDs
+
     /// @brief DL TID-to-Link Mapping negotiated with an MLD (identified by its MLD address)
     std::unordered_map<Mac48Address, WifiTidLinkMapping, WifiAddressHash> m_dlTidLinkMappings;
     /// @brief UL TID-to-Link Mapping negotiated with an MLD (identified by its MLD address)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac-header.cc ns-3.42/src/wifi/model/wifi-mac-header.cc
--- ns-3.41/src/wifi/model/wifi-mac-header.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac-header.cc	2024-05-29 15:29:47.212073800 -0700
@@ -1156,12 +1156,6 @@
     case WIFI_MAC_MGT_PROBE_RESPONSE:
     case WIFI_MAC_MGT_AUTHENTICATION:
     case WIFI_MAC_MGT_DEAUTHENTICATION:
-        PrintFrameControl(os);
-        os << " Duration/ID=" << m_duration << "us"
-           << ", DA=" << m_addr1 << ", SA=" << m_addr2 << ", BSSID=" << m_addr3
-           << ", FragNumber=" << std::hex << (int)m_seqFrag << std::dec
-           << ", SeqNumber=" << m_seqSeq;
-        break;
     case WIFI_MAC_MGT_ACTION:
     case WIFI_MAC_MGT_ACTION_NO_ACK:
         PrintFrameControl(os);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac-queue.cc ns-3.42/src/wifi/model/wifi-mac-queue.cc
--- ns-3.41/src/wifi/model/wifi-mac-queue.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac-queue.cc	2024-05-29 15:29:47.212073800 -0700
@@ -130,7 +130,8 @@
     for (const auto& mpdu : mpdus)
     {
         // fire the Expired trace
-        Simulator::ScheduleNow(&WifiMacQueue::m_traceExpired, this, mpdu);
+        auto fire = [this, mpdu]() -> void { this->m_traceExpired(mpdu); };
+        Simulator::ScheduleNow(fire);
     }
     // notify the scheduler
     if (!mpdus.empty())
@@ -154,7 +155,8 @@
     for (const auto& mpdu : mpdus)
     {
         // fire the Expired trace
-        Simulator::ScheduleNow(&WifiMacQueue::m_traceExpired, this, mpdu);
+        auto fire = [this, mpdu]() -> void { this->m_traceExpired(mpdu); };
+        Simulator::ScheduleNow(fire);
     }
     // notify the scheduler
     if (!mpdus.empty())
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac-queue-container.cc ns-3.42/src/wifi/model/wifi-mac-queue-container.cc
--- ns-3.41/src/wifi/model/wifi-mac-queue-container.cc	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac-queue-container.cc	2024-05-29 15:29:47.212073800 -0700
@@ -25,6 +25,8 @@
 #include "ns3/mac48-address.h"
 #include "ns3/simulator.h"
 
+#include <vector>
+
 namespace ns3
 {
 
@@ -209,14 +211,14 @@
     auto [type, addrType, address, tid] = queueId;
     const std::size_t size = tid.has_value() ? 8 : 7;
 
-    uint8_t buffer[size];
+    std::vector<uint8_t> buffer(size);
     buffer[0] = type;
-    address.CopyTo(buffer + 1);
+    address.CopyTo(&buffer[1]);
     if (tid.has_value())
     {
         buffer[7] = *tid;
     }
 
-    std::string s(buffer, buffer + size);
+    std::string s(buffer.begin(), buffer.end());
     return std::hash<std::string>{}(s);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac-queue-scheduler.h ns-3.42/src/wifi/model/wifi-mac-queue-scheduler.h
--- ns-3.41/src/wifi/model/wifi-mac-queue-scheduler.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac-queue-scheduler.h	2024-05-29 15:29:47.212073800 -0700
@@ -135,9 +135,13 @@
      *
      * \param ac the given Access Category
      * \param mpdu the given MPDU
+     * \param ignoredReasons list of reasons for blocking a link that are ignored
      * \return the list of the IDs of the links the given MPDU can be sent over
      */
-    virtual std::list<uint8_t> GetLinkIds(AcIndex ac, Ptr<const WifiMpdu> mpdu) = 0;
+    virtual std::list<uint8_t> GetLinkIds(
+        AcIndex ac,
+        Ptr<const WifiMpdu> mpdu,
+        const std::list<WifiQueueBlockedReason>& ignoredReasons = {}) = 0;
 
     /**
      * Block the given set of links for the container queues of the given types and
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mac-queue-scheduler-impl.h ns-3.42/src/wifi/model/wifi-mac-queue-scheduler-impl.h
--- ns-3.41/src/wifi/model/wifi-mac-queue-scheduler-impl.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mac-queue-scheduler-impl.h	2024-05-29 15:29:47.212073800 -0700
@@ -26,9 +26,11 @@
 
 #include <algorithm>
 #include <functional>
+#include <iterator>
 #include <list>
 #include <map>
 #include <numeric>
+#include <sstream>
 #include <unordered_map>
 #include <vector>
 
@@ -77,7 +79,9 @@
                                                 std::optional<uint8_t> linkId,
                                                 const WifiContainerQueueId& prevQueueId) final;
     /** \copydoc ns3::WifiMacQueueScheduler::GetLinkIds */
-    std::list<uint8_t> GetLinkIds(AcIndex ac, Ptr<const WifiMpdu> mpdu) final;
+    std::list<uint8_t> GetLinkIds(AcIndex ac,
+                                  Ptr<const WifiMpdu> mpdu,
+                                  const std::list<WifiQueueBlockedReason>& ignoredReasons) final;
     /** \copydoc ns3::WifiMacQueueScheduler::BlockQueues */
     void BlockQueues(WifiQueueBlockedReason reason,
                      AcIndex ac,
@@ -444,14 +448,23 @@
 
 template <class Priority, class Compare>
 std::list<uint8_t>
-WifiMacQueueSchedulerImpl<Priority, Compare>::GetLinkIds(AcIndex ac, Ptr<const WifiMpdu> mpdu)
+WifiMacQueueSchedulerImpl<Priority, Compare>::GetLinkIds(
+    AcIndex ac,
+    Ptr<const WifiMpdu> mpdu,
+    const std::list<WifiQueueBlockedReason>& ignoredReasons)
 {
     auto queueInfoIt = InitQueueInfo(ac, mpdu);
     std::list<uint8_t> linkIds;
 
     // include only links that are not blocked in the returned list
-    for (const auto& [linkId, mask] : queueInfoIt->second.linkIds)
+    for (auto [linkId, mask] : queueInfoIt->second.linkIds)
     {
+        // reset the bits of the mask corresponding to the reasons to ignore
+        for (const auto reason : ignoredReasons)
+        {
+            mask.reset(static_cast<std::size_t>(reason));
+        }
+
         if (mask.none())
         {
             linkIds.emplace_back(linkId);
@@ -473,7 +486,12 @@
     const std::set<uint8_t>& tids,
     const std::set<uint8_t>& linkIds)
 {
-    NS_LOG_FUNCTION(this << block << reason << ac << rxAddress << txAddress);
+    std::stringstream ss;
+    if (g_log.IsEnabled(ns3::LOG_FUNCTION))
+    {
+        std::copy(linkIds.cbegin(), linkIds.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+    }
+    NS_LOG_FUNCTION(this << block << reason << ac << rxAddress << txAddress << ss.str());
     std::list<WifiMacHeader> headers;
 
     for (const auto queueType : types)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-mgt-header.h ns-3.42/src/wifi/model/wifi-mgt-header.h
--- ns-3.41/src/wifi/model/wifi-mgt-header.h	2024-02-09 14:44:08.601795200 -0800
+++ ns-3.42/src/wifi/model/wifi-mgt-header.h	2024-05-29 15:29:47.212073800 -0700
@@ -325,9 +325,9 @@
                                                          to the Per-STA Profile subelement */
 };
 
-/**
- * Implementation of the templates declared above.
- */
+//
+// Implementation of the templates declared above.
+//
 
 template <typename Derived, typename... Elems>
 template <typename T, std::enable_if_t<(std::is_same_v<std::vector<T>, Elems> + ...) == 0, int>>
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-net-device.cc ns-3.42/src/wifi/model/wifi-net-device.cc
--- ns-3.41/src/wifi/model/wifi-net-device.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-net-device.cc	2024-05-29 15:29:47.212073800 -0700
@@ -254,6 +254,7 @@
 {
     m_phys.clear();
     m_phys.push_back(phy);
+    phy->SetPhyId(0);
     m_linkUp = true;
     CompleteConfig();
 }
@@ -264,6 +265,10 @@
     NS_ABORT_MSG_IF(phys.size() > 1 && !m_ehtConfiguration,
                     "Multiple PHYs only allowed for 11be multi-link devices");
     m_phys = phys;
+    for (std::size_t id = 0; id < phys.size(); ++id)
+    {
+        m_phys.at(id)->SetPhyId(id);
+    }
     m_linkUp = true;
     CompleteConfig();
 }
@@ -478,17 +483,7 @@
 WifiNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
 {
     NS_LOG_FUNCTION(this << packet << dest << protocolNumber);
-    NS_ASSERT(Mac48Address::IsMatchingType(dest));
-
-    Mac48Address realTo = Mac48Address::ConvertFrom(dest);
-
-    LlcSnapHeader llc;
-    llc.SetType(protocolNumber);
-    packet->AddHeader(llc);
-
-    m_mac->NotifyTx(packet);
-    m_mac->Enqueue(packet, realTo);
-    return true;
+    return DoSend(packet, std::nullopt, dest, protocolNumber);
 }
 
 Ptr<Node>
@@ -579,18 +574,41 @@
                         uint16_t protocolNumber)
 {
     NS_LOG_FUNCTION(this << packet << source << dest << protocolNumber);
-    NS_ASSERT(Mac48Address::IsMatchingType(dest));
-    NS_ASSERT(Mac48Address::IsMatchingType(source));
+    return DoSend(packet, source, dest, protocolNumber);
+}
 
-    Mac48Address realTo = Mac48Address::ConvertFrom(dest);
-    Mac48Address realFrom = Mac48Address::ConvertFrom(source);
+bool
+WifiNetDevice::DoSend(Ptr<Packet> packet,
+                      std::optional<Address> source,
+                      const Address& dest,
+                      uint16_t protocolNumber)
+{
+    NS_LOG_FUNCTION(this << packet << dest << protocolNumber << source.value_or(Address()));
+
+    if (source)
+    {
+        NS_ASSERT_MSG(Mac48Address::IsMatchingType(*source),
+                      *source << " is not compatible with a Mac48Address");
+    }
+    NS_ASSERT_MSG(Mac48Address::IsMatchingType(dest),
+                  dest << " is not compatible with a Mac48Address");
+
+    auto realTo = Mac48Address::ConvertFrom(dest);
 
     LlcSnapHeader llc;
     llc.SetType(protocolNumber);
     packet->AddHeader(llc);
 
     m_mac->NotifyTx(packet);
-    m_mac->Enqueue(packet, realTo, realFrom);
+    if (source)
+    {
+        auto realFrom = Mac48Address::ConvertFrom(*source);
+        m_mac->Enqueue(packet, realTo, realFrom);
+    }
+    else
+    {
+        m_mac->Enqueue(packet, realTo);
+    }
 
     return true;
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-net-device.h ns-3.42/src/wifi/model/wifi-net-device.h
--- ns-3.41/src/wifi/model/wifi-net-device.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-net-device.h	2024-05-29 15:29:47.212073800 -0700
@@ -25,6 +25,7 @@
 #include "ns3/net-device.h"
 #include "ns3/traced-callback.h"
 
+#include <optional>
 #include <vector>
 
 namespace ns3
@@ -239,6 +240,20 @@
      */
     void CompleteConfig();
 
+    /**
+     * Send a packet
+     *
+     * \param packet packet sent from upper layers
+     * \param source source mac address (if provided)
+     * \param dest destination mac address
+     * \param protocolNumber type of payload contained in this packet
+     * \returns true if successful, false otherwise
+     */
+    bool DoSend(Ptr<Packet> packet,
+                std::optional<Address> source,
+                const Address& dest,
+                uint16_t protocolNumber);
+
     Ptr<Node> m_node;                                             //!< the node
     std::vector<Ptr<WifiPhy>> m_phys;                             //!< the phy objects
     Ptr<WifiMac> m_mac;                                           //!< the MAC
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-opt-field.h ns-3.42/src/wifi/model/wifi-opt-field.h
--- ns-3.41/src/wifi/model/wifi-opt-field.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/wifi-opt-field.h	2024-05-29 15:29:47.212073800 -0700
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2024 Universita' degli Studi di Napoli Federico II
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Stefano Avallone <stavallo@unina.it>
+ */
+
+#ifndef WIFI_OPT_FIELD_H
+#define WIFI_OPT_FIELD_H
+
+#include <functional>
+#include <optional>
+
+namespace ns3
+{
+
+/**
+ * \ingroup wifi
+ *
+ * OptFieldWithPresenceInd is a class modeling an optional field (in an Information Element, a
+ * management frame, etc.) having an associated Presence Indicator bit. This class is a wrapper
+ * around std::optional (most of its functions are exposed, more can be added if needed) that
+ * additionally sets the Presence Indicator flag appropriately when operations like reset or
+ * assignment of a value are performed on the optional field.
+ */
+template <typename T>
+class OptFieldWithPresenceInd
+{
+  public:
+    /// @brief constructor
+    /// @param presenceFlag the Presence Indicator flag
+    OptFieldWithPresenceInd(bool& presenceFlag);
+
+    /// @brief Destroy the value (if any) contained in the optional field.
+    /// @return a reference to this object
+    constexpr OptFieldWithPresenceInd& operator=(std::nullopt_t);
+
+    /// @brief Assign the given value to the optional field
+    /// @param other the given value
+    /// @return a reference to this object
+    constexpr OptFieldWithPresenceInd& operator=(const std::optional<T>& other);
+
+    /// @brief Assign the given value to the optional field
+    /// @param other the given value
+    /// @return a reference to this object
+    constexpr OptFieldWithPresenceInd& operator=(std::optional<T>&& other);
+
+    /// @brief Operator bool
+    /// @return whether this object contains a value
+    constexpr explicit operator bool() const;
+
+    /// @brief Check whether this object contains a value
+    /// @return whether this object contains a value
+    constexpr bool has_value() const;
+
+    /// @return a pointer to the contained value
+    constexpr const T* operator->() const;
+
+    /// @return a pointer to the contained value
+    constexpr T* operator->();
+
+    /// @return a reference to the contained value
+    constexpr const T& operator*() const;
+
+    /// @return a reference to the contained value
+    constexpr T& operator*();
+
+    /// @brief Construct the contained value in-place
+    /// @tparam Args the type of arguments to pass to the constructor
+    /// @param args the arguments to pass to the constructor
+    /// @return a reference to the new contained value
+    template <class... Args>
+    constexpr T& emplace(Args&&... args);
+
+    /// @brief Destroy the value (if any) contained in the optional field
+    constexpr void reset();
+
+  private:
+    std::optional<T> m_field;                    ///< the optional field
+    std::reference_wrapper<bool> m_presenceFlag; ///< the Presence Indicator flag
+};
+
+} // namespace ns3
+
+/***************************************************************
+ *  Implementation of the templates declared above.
+ ***************************************************************/
+
+namespace ns3
+{
+
+template <typename T>
+OptFieldWithPresenceInd<T>::OptFieldWithPresenceInd(bool& presenceFlag)
+    : m_presenceFlag(presenceFlag)
+{
+    m_presenceFlag.get() = false;
+}
+
+template <typename T>
+constexpr OptFieldWithPresenceInd<T>&
+OptFieldWithPresenceInd<T>::operator=(std::nullopt_t)
+{
+    m_field.reset();
+    m_presenceFlag.get() = false;
+    return *this;
+}
+
+template <typename T>
+constexpr OptFieldWithPresenceInd<T>&
+OptFieldWithPresenceInd<T>::operator=(const std::optional<T>& other)
+{
+    m_field = other;
+    m_presenceFlag.get() = other.has_value();
+    return *this;
+}
+
+template <typename T>
+constexpr OptFieldWithPresenceInd<T>&
+OptFieldWithPresenceInd<T>::operator=(std::optional<T>&& other)
+{
+    m_field = std::move(other);
+    m_presenceFlag.get() = other.has_value();
+    return *this;
+}
+
+template <typename T>
+constexpr OptFieldWithPresenceInd<T>::operator bool() const
+{
+    return m_field.has_value();
+}
+
+template <typename T>
+constexpr bool
+OptFieldWithPresenceInd<T>::has_value() const
+{
+    return m_field.has_value();
+}
+
+template <typename T>
+constexpr const T*
+OptFieldWithPresenceInd<T>::operator->() const
+{
+    return &(*m_field);
+}
+
+template <typename T>
+constexpr T*
+OptFieldWithPresenceInd<T>::operator->()
+{
+    return &(*m_field);
+}
+
+template <typename T>
+constexpr const T&
+OptFieldWithPresenceInd<T>::operator*() const
+{
+    return *m_field;
+}
+
+template <typename T>
+constexpr T&
+OptFieldWithPresenceInd<T>::operator*()
+{
+    return *m_field;
+}
+
+template <typename T>
+template <class... Args>
+constexpr T&
+OptFieldWithPresenceInd<T>::emplace(Args&&... args)
+{
+    m_field.emplace(std::forward<Args>(args)...);
+    m_presenceFlag.get() = true;
+    return *m_field;
+}
+
+template <typename T>
+constexpr void
+OptFieldWithPresenceInd<T>::reset()
+{
+    m_field.reset();
+    m_presenceFlag.get() = false;
+}
+
+} // namespace ns3
+
+#endif /* WIFI_OPT_FIELD_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy.cc ns-3.42/src/wifi/model/wifi-phy.cc
--- ns-3.41/src/wifi/model/wifi-phy.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy.cc	2024-05-29 15:29:47.212073800 -0700
@@ -47,6 +47,13 @@
 
 #include <algorithm>
 
+#undef NS_LOG_APPEND_CONTEXT
+#define NS_LOG_APPEND_CONTEXT                                                                      \
+    WIFI_PHY_NS_LOG_APPEND_CONTEXT(                                                                \
+        (m_device && (m_device->GetNPhys() > m_phyId) && m_device->GetPhy(m_phyId)                 \
+             ? m_device->GetPhy(m_phyId)                                                           \
+             : nullptr))
+
 namespace ns3
 {
 
@@ -334,6 +341,11 @@
                             "has been dropped by the device during reception",
                             MakeTraceSourceAccessor(&WifiPhy::m_phyRxDropTrace),
                             "ns3::Packet::TracedCallback")
+            .AddTraceSource("PhyRxPpduDrop",
+                            "Trace source indicating a ppdu "
+                            "has been dropped by the device during reception",
+                            MakeTraceSourceAccessor(&WifiPhy::m_phyRxPpduDropTrace),
+                            "ns3::WifiPhy::PhyRxPpduDropTracedCallback")
             .AddTraceSource("MonitorSnifferRx",
                             "Trace source simulating a wifi device in monitor mode "
                             "sniffing all received frames",
@@ -343,12 +355,17 @@
                             "Trace source simulating the capability of a wifi device "
                             "in monitor mode to sniff all frames being transmitted",
                             MakeTraceSourceAccessor(&WifiPhy::m_phyMonitorSniffTxTrace),
-                            "ns3::WifiPhy::MonitorSnifferTxTracedCallback");
+                            "ns3::WifiPhy::MonitorSnifferTxTracedCallback")
+            .AddTraceSource("SignalTransmission",
+                            "Trace start of signal transmission",
+                            MakeTraceSourceAccessor(&WifiPhy::m_signalTransmissionCb),
+                            "ns3::SpectrumWifiPhy::SignalTransmissionCallback");
     return tid;
 }
 
 WifiPhy::WifiPhy()
-    : m_txMpduReferenceNumber(0xffffffff),
+    : m_phyId(0),
+      m_txMpduReferenceNumber(0xffffffff),
       m_rxMpduReferenceNumber(0xffffffff),
       m_endPhyRxEvent(),
       m_endTxEvent(),
@@ -409,8 +426,6 @@
 {
     NS_LOG_FUNCTION(this);
 
-    Reset();
-
     m_device = nullptr;
     m_mobility = nullptr;
     m_frameCaptureModel = nullptr;
@@ -425,6 +440,9 @@
     m_random = nullptr;
     m_state = nullptr;
 
+    Reset();
+
+    // this should be done after calling the Reset function
     for (auto& phyEntity : m_phyEntities)
     {
         phyEntity.second = nullptr;
@@ -479,13 +497,13 @@
 WifiPhy::SetRxSensitivity(double threshold)
 {
     NS_LOG_FUNCTION(this << threshold);
-    m_rxSensitivityW = DbmToW(threshold);
+    m_rxSensitivityDbm = threshold;
 }
 
 double
 WifiPhy::GetRxSensitivity() const
 {
-    return WToDbm(m_rxSensitivityW);
+    return m_rxSensitivityDbm;
 }
 
 void
@@ -628,8 +646,22 @@
 }
 
 void
+WifiPhy::SetPhyId(uint8_t phyId)
+{
+    NS_LOG_FUNCTION(this << phyId);
+    m_phyId = phyId;
+}
+
+uint8_t
+WifiPhy::GetPhyId() const
+{
+    return m_phyId;
+}
+
+void
 WifiPhy::SetInterferenceHelper(const Ptr<InterferenceHelper> helper)
 {
+    NS_LOG_FUNCTION(this << helper);
     m_interference = helper;
     m_interference->SetNoiseFigure(DbToRatio(m_noiseFigureDb));
     m_interference->SetNumberOfReceiveAntennas(m_numberOfAntennas);
@@ -638,6 +670,7 @@
 void
 WifiPhy::SetErrorRateModel(const Ptr<ErrorRateModel> model)
 {
+    NS_LOG_FUNCTION(this << model);
     NS_ASSERT(m_interference);
     m_interference->SetErrorRateModel(model);
 }
@@ -751,8 +784,7 @@
 void
 WifiPhy::AddStaticPhyEntity(WifiModulationClass modulation, Ptr<PhyEntity> phyEntity)
 {
-    NS_LOG_FUNCTION(modulation);
-    NS_ASSERT_MSG(GetStaticPhyEntities().find(modulation) == GetStaticPhyEntities().end(),
+    NS_ASSERT_MSG(!GetStaticPhyEntities().contains(modulation),
                   "The PHY entity has already been added. The setting should only be done once per "
                   "modulation class");
     GetStaticPhyEntities()[modulation] = phyEntity;
@@ -762,7 +794,7 @@
 WifiPhy::AddPhyEntity(WifiModulationClass modulation, Ptr<PhyEntity> phyEntity)
 {
     NS_LOG_FUNCTION(this << modulation);
-    NS_ABORT_MSG_IF(GetStaticPhyEntities().find(modulation) == GetStaticPhyEntities().end(),
+    NS_ABORT_MSG_IF(!GetStaticPhyEntities().contains(modulation),
                     "Cannot add an unimplemented PHY to supported list. Update the former first.");
     NS_ASSERT_MSG(m_phyEntities.find(modulation) == m_phyEntities.end(),
                   "The PHY entity has already been added. The setting should only be done once per "
@@ -1617,6 +1649,13 @@
 }
 
 void
+WifiPhy::NotifyRxPpduDrop(Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason)
+{
+    NotifyRxDrop(GetAddressedPsduInPpdu(ppdu), reason);
+    m_phyRxPpduDropTrace(ppdu, reason);
+}
+
+void
 WifiPhy::NotifyMonitorSniffRx(Ptr<const WifiPsdu> psdu,
                               uint16_t channelFreqMhz,
                               WifiTxVector txVector,
@@ -1777,11 +1816,19 @@
     Time txDuration = CalculateTxDuration(psdus, txVector, GetPhyBand());
 
     bool noEndPreambleDetectionEvent = true;
-    for (const auto& it : m_phyEntities)
+    for (const auto& [mc, entity] : m_phyEntities)
     {
-        noEndPreambleDetectionEvent &= it.second->NoEndPreambleDetectionEvents();
+        noEndPreambleDetectionEvent =
+            noEndPreambleDetectionEvent && entity->NoEndPreambleDetectionEvents();
     }
-    if (!noEndPreambleDetectionEvent || m_currentEvent)
+    if (!noEndPreambleDetectionEvent && !m_currentEvent)
+    {
+        // PHY is in the initial few microseconds during which the
+        // start of RX has occurred but the preamble detection period
+        // has not elapsed
+        AbortCurrentReception(SIGNAL_DETECTION_ABORTED_BY_TX);
+    }
+    else if (!noEndPreambleDetectionEvent || m_currentEvent)
     {
         AbortCurrentReception(RECEPTION_ABORTED_BY_TX);
     }
@@ -1824,17 +1871,23 @@
     }
 
     m_endTxEvent =
-        Simulator::Schedule(txDuration, &WifiPhy::NotifyTxEnd, this, psdus); // TODO: fix for MU
+        Simulator::Schedule(txDuration, &WifiPhy::TxDone, this, psdus); // TODO: fix for MU
 
     StartTx(ppdu);
     ppdu->ResetTxVector();
 
     m_channelAccessRequested = false;
     m_powerRestricted = false;
+}
 
-    Simulator::Schedule(txDuration, &WifiPhy::Reset, this);
-
-    Simulator::Schedule(txDuration, &WifiPhy::SwitchMaybeToCcaBusy, this, nullptr);
+void
+WifiPhy::TxDone(const WifiConstPsduMap& psdus)
+{
+    NS_LOG_FUNCTION(this << psdus);
+    NotifyTxEnd(psdus);
+    Reset();
+    // we might have received signals during TX
+    SwitchMaybeToCcaBusy();
 }
 
 uint64_t
@@ -1855,6 +1908,16 @@
 {
     NS_LOG_FUNCTION(this);
     m_currentPreambleEvents.clear();
+    bool noEndPreambleDetectionEvent = true;
+    for (const auto& [mc, entity] : m_phyEntities)
+    {
+        noEndPreambleDetectionEvent =
+            noEndPreambleDetectionEvent && entity->NoEndPreambleDetectionEvents();
+    }
+    if (m_interference && (m_currentEvent || !noEndPreambleDetectionEvent))
+    {
+        m_interference->NotifyRxEnd(Simulator::Now(), GetCurrentFrequencyRange());
+    }
     m_currentEvent = nullptr;
     for (auto& phyEntity : m_phyEntities)
     {
@@ -1882,7 +1945,7 @@
         // TODO find a fallback PHY for receiving the PPDU (e.g. 11a for 11ax due to preamble
         // structure)
         NS_LOG_DEBUG("Unsupported modulation received (" << modulation << "), consider as noise");
-        m_interference->Add(ppdu, rxDuration, rxPowersW);
+        m_interference->Add(ppdu, rxDuration, rxPowersW, GetCurrentFrequencyRange());
         SwitchMaybeToCcaBusy();
     }
 }
@@ -1890,7 +1953,7 @@
 bool
 WifiPhy::IsReceivingPhyHeader() const
 {
-    return m_endPhyRxEvent.IsRunning();
+    return m_endPhyRxEvent.IsPending();
 }
 
 void
@@ -2122,6 +2185,14 @@
     if (reason != OBSS_PD_CCA_RESET ||
         m_currentEvent) // Otherwise abort has already been called previously
     {
+        if (reason == SIGNAL_DETECTION_ABORTED_BY_TX)
+        {
+            for (auto signalDetectEvent : m_currentPreambleEvents)
+            {
+                NotifyRxPpduDrop(signalDetectEvent.second->GetPpdu(),
+                                 SIGNAL_DETECTION_ABORTED_BY_TX);
+            }
+        }
         for (auto& phyEntity : m_phyEntities)
         {
             phyEntity.second->CancelAllEvents();
@@ -2132,7 +2203,7 @@
         {
             return;
         }
-        NotifyRxDrop(GetAddressedPsduInPpdu(m_currentEvent->GetPpdu()), reason);
+        NotifyRxPpduDrop(m_currentEvent->GetPpdu(), reason);
         if (reason == OBSS_PD_CCA_RESET)
         {
             m_state->SwitchFromRxAbort(GetChannelWidth());
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy-common.cc ns-3.42/src/wifi/model/wifi-phy-common.cc
--- ns-3.41/src/wifi/model/wifi-phy-common.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy-common.cc	2024-05-29 15:29:47.212073800 -0700
@@ -257,11 +257,13 @@
         return 20;
     case WIFI_MOD_CLASS_HT:
         return 40;
+    // NOLINTBEGIN(bugprone-branch-clone)
     case WIFI_MOD_CLASS_VHT:
     case WIFI_MOD_CLASS_HE:
         return 160;
     case WIFI_MOD_CLASS_EHT:
-        return 160; // TODO update when 320 MHz channels are supported
+        return 160; // TODO update when 320 MHz channels are supported and remove clang-tidy guards
+    // NOLINTEND(bugprone-branch-clone)
     default:
         NS_ABORT_MSG("Unknown modulation class: " << modulation);
         return 0;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy-common.h ns-3.42/src/wifi/model/wifi-phy-common.h
--- ns-3.41/src/wifi/model/wifi-phy-common.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy-common.h	2024-05-29 15:29:47.212073800 -0700
@@ -22,11 +22,11 @@
 #ifndef WIFI_PHY_COMMON_H
 #define WIFI_PHY_COMMON_H
 
+#include "wifi-spectrum-value-helper.h"
 #include "wifi-standards.h"
 
 #include "ns3/fatal-error.h"
 #include "ns3/ptr.h"
-#include "ns3/wifi-spectrum-value-helper.h"
 
 #include <ostream>
 
@@ -428,7 +428,8 @@
     PPDU_TOO_LATE,
     FILTERED,
     DMG_HEADER_FAILURE,
-    DMG_ALLOCATION_ENDED
+    DMG_ALLOCATION_ENDED,
+    SIGNAL_DETECTION_ABORTED_BY_TX
 };
 
 /**
@@ -489,6 +490,8 @@
         return (os << "DMG_HEADER_FAILURE");
     case DMG_ALLOCATION_ENDED:
         return (os << "DMG_ALLOCATION_ENDED");
+    case SIGNAL_DETECTION_ABORTED_BY_TX:
+        return (os << "SIGNAL_DETECTION_ABORTED_BY_TX");
     case UNKNOWN:
     default:
         NS_FATAL_ERROR("Unknown reason");
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy.h ns-3.42/src/wifi/model/wifi-phy.h
--- ns-3.41/src/wifi/model/wifi-phy.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy.h	2024-05-29 15:29:47.212073800 -0700
@@ -30,6 +30,18 @@
 
 #include <limits>
 
+#define WIFI_PHY_NS_LOG_APPEND_CONTEXT(phy)                                                        \
+    {                                                                                              \
+        if (DynamicCast<const WifiPhy>(phy))                                                       \
+        {                                                                                          \
+            std::clog << "[index=" << +phy->GetPhyId() << "][channel="                             \
+                      << (phy->GetOperatingChannel().IsSet()                                       \
+                              ? std::to_string(+phy->GetOperatingChannel().GetNumber())            \
+                              : "UNKNOWN")                                                         \
+                      << "][band=" << phy->GetPhyBand() << "] ";                                   \
+        }                                                                                          \
+    }
+
 namespace ns3
 {
 
@@ -596,12 +608,26 @@
      * Public method used to fire a PhyRxDrop trace.
      * Implemented for encapsulation purposes.
      *
+     * \note This method is called also by NotifyRxPpduDrop and is left
+     * in the public API for backward compatibility reasons.  Do not
+     * call both this method and the newer NotifyRxPpduDrop().  Instead,
+     * call NotifyRxPpduDrop() and it will call this method also.
+     *
      * \param psdu the PSDU being transmitted
      * \param reason the reason the packet was dropped
      */
     void NotifyRxDrop(Ptr<const WifiPsdu> psdu, WifiPhyRxfailureReason reason);
 
     /**
+     * Public method used to fire a PhyRxPpduDrop trace.
+     * Implemented for encapsulation purposes.  This method also
+     * calls the PhyRxDrop trace.
+     *
+     * \param ppdu the PSDU being transmitted
+     * \param reason the reason the packet was dropped
+     */
+    void NotifyRxPpduDrop(Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason);
+    /**
      * Public method used to fire a MonitorSniffer trace for a wifi PSDU being received.
      * Implemented for encapsulation purposes.
      * This method will extract all MPDUs if packet is an A-MPDU and will fire tracedCallback.
@@ -732,6 +758,15 @@
     typedef void (*PhyRxPayloadBeginTracedCallback)(WifiTxVector txVector, Time psduDuration);
 
     /**
+     * TracedCallback signature for start of PSDU reception events.
+     *
+     * \param txVector the TXVECTOR decoded from the PHY header
+     * \param psduDuration the duration of the PSDU
+     */
+    typedef void (*PhyRxPpduDropTracedCallback)(Ptr<const WifiPpdu> ppdu,
+                                                WifiPhyRxfailureReason reason);
+
+    /**
      * Assign a fixed random variable stream number to the random variables
      * used by this model. Return the number of streams (possibly zero) that
      * have been assigned.
@@ -987,6 +1022,20 @@
     bool GetShortPhyPreambleSupported() const;
 
     /**
+     * Set the index allocated to this PHY
+     *
+     * \param phyId the ID allocated to this PHY
+     */
+    void SetPhyId(uint8_t phyId);
+
+    /**
+     * Get the index allocated to this PHY
+     *
+     * \return the ID allocated to this PHY
+     */
+    uint8_t GetPhyId() const;
+
+    /**
      * Sets the interference helper.
      *
      * \param helper the interference helper
@@ -1207,6 +1256,15 @@
      */
     uint32_t GetSubcarrierSpacing() const;
 
+    /**
+     * Callback invoked when the PHY model starts to transmit a signal
+     *
+     * \param ppdu The PPDU being transmitted
+     * \param txVector txVector used for transmitting the PPDU
+     */
+    typedef void (*SignalTransmissionCallback)(Ptr<const WifiPpdu> ppdu,
+                                               const WifiTxVector& txVector);
+
   protected:
     void DoInitialize() override;
     void DoDispose() override;
@@ -1256,6 +1314,8 @@
      */
     void AddPhyEntity(WifiModulationClass modulation, Ptr<PhyEntity> phyEntity);
 
+    uint8_t m_phyId; //!< the index of the PHY in the vector of PHYs held by the WifiNetDevice
+
     Ptr<InterferenceHelper>
         m_interference; //!< Pointer to a helper responsible for interference computations
 
@@ -1297,6 +1357,9 @@
      */
     std::map<WifiModulationClass, Ptr<PhyEntity>> m_phyEntities;
 
+    TracedCallback<Ptr<const WifiPpdu>, const WifiTxVector&>
+        m_signalTransmissionCb; //!< Signal Transmission callback
+
   private:
     /**
      * Configure WifiPhy with appropriate channel frequency and
@@ -1362,6 +1425,12 @@
     void AbortCurrentReception(WifiPhyRxfailureReason reason);
 
     /**
+     * Callback function when a transmission is completed
+     * \param psdus the PSDUs that have been sent
+     */
+    void TxDone(const WifiConstPsduMap& psdus);
+
+    /**
      * Get the PSDU addressed to that PHY in a PPDU (useful for MU PPDU).
      *
      * \param ppdu the PPDU to extract the PSDU from
@@ -1440,6 +1509,11 @@
     TracedCallback<Ptr<const Packet>, WifiPhyRxfailureReason> m_phyRxDropTrace;
 
     /**
+     * The trace source fired when the PHY layer drops a packet it has received.
+     */
+    TracedCallback<Ptr<const WifiPpdu>, WifiPhyRxfailureReason> m_phyRxPpduDropTrace;
+
+    /**
      * A trace source that emulates a Wi-Fi device in monitor mode
      * sniffing a packet being received.
      *
@@ -1500,7 +1574,7 @@
     Time m_ackTxTime;      //!< estimated Ack TX time
     Time m_blockAckTxTime; //!< estimated BlockAck TX time
 
-    double m_rxSensitivityW;  //!< Receive sensitivity threshold in watts
+    double m_rxSensitivityDbm; //!< Receive sensitivity threshold in dBm
     double m_ccaEdThresholdW; //!< Clear channel assessment (CCA) energy detection (ED) threshold in
                               //!< watts
     double m_ccaSensitivityThresholdW; //!< Clear channel assessment (CCA) modulation and coding
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy-operating-channel.cc ns-3.42/src/wifi/model/wifi-phy-operating-channel.cc
--- ns-3.41/src/wifi/model/wifi-phy-operating-channel.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy-operating-channel.cc	2024-05-29 15:29:47.212073800 -0700
@@ -251,7 +251,7 @@
     {std::make_tuple(71, 6305, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
     {std::make_tuple(87, 6385, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
     {std::make_tuple(103, 6465, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
-    {std::make_tuple(119, 6585, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
+    {std::make_tuple(119, 6545, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
     {std::make_tuple(135, 6625, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
     {std::make_tuple(151, 6705, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
     {std::make_tuple(167, 6785, 80, WIFI_PHY_OFDM_CHANNEL, WIFI_PHY_BAND_6GHZ)},
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy-state.h ns-3.42/src/wifi/model/wifi-phy-state.h
--- ns-3.41/src/wifi/model/wifi-phy-state.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy-state.h	2024-05-29 15:29:47.212073800 -0700
@@ -21,18 +21,22 @@
 #ifndef WIFI_PHY_STATE_H
 #define WIFI_PHY_STATE_H
 
+#include "ns3/deprecated.h"
 #include "ns3/fatal-error.h"
 
+namespace ns3
+{
+
 /**
  * The state of the PHY layer.
  */
 /// State enumeration
-enum WifiPhyState
+enum class WifiPhyState
 {
     /**
      * The PHY layer is IDLE.
      */
-    IDLE,
+    IDLE = 0,
     /**
      * The PHY layer has sense the medium busy through the CCA mechanism
      */
@@ -71,19 +75,19 @@
 {
     switch (state)
     {
-    case IDLE:
+    case WifiPhyState::IDLE:
         return (os << "IDLE");
-    case CCA_BUSY:
+    case WifiPhyState::CCA_BUSY:
         return (os << "CCA_BUSY");
-    case TX:
+    case WifiPhyState::TX:
         return (os << "TX");
-    case RX:
+    case WifiPhyState::RX:
         return (os << "RX");
-    case SWITCHING:
+    case WifiPhyState::SWITCHING:
         return (os << "SWITCHING");
-    case SLEEP:
+    case WifiPhyState::SLEEP:
         return (os << "SLEEP");
-    case OFF:
+    case WifiPhyState::OFF:
         return (os << "OFF");
     default:
         NS_FATAL_ERROR("Invalid state");
@@ -91,4 +95,23 @@
     }
 }
 
+} // namespace ns3
+
+NS_DEPRECATED_3_42("Use WifiPhyState::IDLE instead")
+static constexpr auto IDLE = ns3::WifiPhyState::IDLE; //!< \deprecated See WifiPhyState::IDLE
+NS_DEPRECATED_3_42("Use WifiPhyState::CCA_BUSY instead")
+static constexpr auto CCA_BUSY =
+    ns3::WifiPhyState::CCA_BUSY; //!< \deprecated See WifiPhyState::CCA_BUSY
+NS_DEPRECATED_3_42("Use WifiPhyState::TX instead")
+static constexpr auto TX = ns3::WifiPhyState::TX; //!< \deprecated See WifiPhyState::TX
+NS_DEPRECATED_3_42("Use WifiPhyState::RX instead")
+static constexpr auto RX = ns3::WifiPhyState::RX; //!< \deprecated See WifiPhyState::RX
+NS_DEPRECATED_3_42("Use WifiPhyState::SWITCHING instead")
+static constexpr auto SWITCHING =
+    ns3::WifiPhyState::SWITCHING; //!< \deprecated See WifiPhyState::SWITCHING
+NS_DEPRECATED_3_42("Use WifiPhyState::SLEEP instead")
+static constexpr auto SLEEP = ns3::WifiPhyState::SLEEP; //!< \deprecated See WifiPhyState::SLEEP
+NS_DEPRECATED_3_42("Use WifiPhyState::OFF instead")
+static constexpr auto OFF = ns3::WifiPhyState::OFF; //!< \deprecated See WifiPhyState::OFF
+
 #endif /* WIFI_PHY_STATE_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy-state-helper.cc ns-3.42/src/wifi/model/wifi-phy-state-helper.cc
--- ns-3.41/src/wifi/model/wifi-phy-state-helper.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy-state-helper.cc	2024-05-29 15:29:47.212073800 -0700
@@ -55,6 +55,11 @@
                             "A packet has been received successfully.",
                             MakeTraceSourceAccessor(&WifiPhyStateHelper::m_rxOkTrace),
                             "ns3::WifiPhyStateHelper::RxOkTracedCallback")
+            .AddTraceSource(
+                "RxOutcome",
+                "The outcome of the decoding of the PPDU, including MPDU decoding status",
+                MakeTraceSourceAccessor(&WifiPhyStateHelper::m_rxOutcomeTrace),
+                "ns3::WifiPhyStateHelper::RxOutcomeTracedCallback")
             .AddTraceSource("RxError",
                             "A packet has been received unsuccessfuly.",
                             MakeTraceSourceAccessor(&WifiPhyStateHelper::m_rxErrorTrace),
@@ -70,16 +75,20 @@
     : NS_LOG_TEMPLATE_DEFINE("WifiPhyStateHelper"),
       m_sleeping(false),
       m_isOff(false),
-      m_endTx(Seconds(0)),
-      m_endRx(Seconds(0)),
-      m_endCcaBusy(Seconds(0)),
-      m_endSwitching(Seconds(0)),
-      m_startTx(Seconds(0)),
-      m_startRx(Seconds(0)),
-      m_startCcaBusy(Seconds(0)),
-      m_startSwitching(Seconds(0)),
-      m_startSleep(Seconds(0)),
-      m_previousStateChangeTime(Seconds(0))
+      m_endTx(Time{0}),
+      m_endRx(Time{0}),
+      m_endCcaBusy(Time{0}),
+      m_endSwitching(Time{0}),
+      m_endSleep(Time{0}),
+      m_endOff(Time{0}),
+      m_endIdle(Time{0}),
+      m_startTx(Time{0}),
+      m_startRx(Time{0}),
+      m_startCcaBusy(Time{0}),
+      m_startSwitching(Time{0}),
+      m_startSleep(Time{0}),
+      m_startOff(Time{0}),
+      m_previousStateChangeTime(Time{0})
 {
     NS_LOG_FUNCTION(this);
 }
@@ -195,9 +204,54 @@
     return m_endRx;
 }
 
+Time
+WifiPhyStateHelper::GetLastTime(std::initializer_list<WifiPhyState> states) const
+{
+    Time last{0};
+    auto currentState = GetState();
+
+    for (auto state : states)
+    {
+        if (state == currentState)
+        {
+            return Simulator::Now();
+        }
+
+        switch (state)
+        {
+        case WifiPhyState::RX:
+            last = std::max(last, m_endRx);
+            break;
+        case WifiPhyState::TX:
+            last = std::max(last, m_endTx);
+            break;
+        case WifiPhyState::CCA_BUSY:
+            last = std::max(last, m_endCcaBusy);
+            break;
+        case WifiPhyState::SWITCHING:
+            last = std::max(last, m_endSwitching);
+            break;
+        case WifiPhyState::SLEEP:
+            last = std::max(last, m_endSleep);
+            break;
+        case WifiPhyState::OFF:
+            last = std::max(last, m_endOff);
+            break;
+        case WifiPhyState::IDLE:
+            last = std::max(last, m_endIdle);
+            break;
+        default:
+            NS_FATAL_ERROR("Invalid WifiPhy state " << state);
+        }
+    }
+    NS_ASSERT(last <= Simulator::Now());
+    return last;
+}
+
 WifiPhyState
 WifiPhyStateHelper::GetState() const
 {
+    const auto now = Simulator::Now();
     if (m_isOff)
     {
         return WifiPhyState::OFF;
@@ -206,19 +260,19 @@
     {
         return WifiPhyState::SLEEP;
     }
-    else if (m_endTx > Simulator::Now())
+    else if (m_endTx > now)
     {
         return WifiPhyState::TX;
     }
-    else if (m_endRx > Simulator::Now())
+    else if (m_endRx > now)
     {
         return WifiPhyState::RX;
     }
-    else if (m_endSwitching > Simulator::Now())
+    else if (m_endSwitching > now)
     {
         return WifiPhyState::SWITCHING;
     }
-    else if (m_endCcaBusy > Simulator::Now())
+    else if (m_endCcaBusy > now)
     {
         return WifiPhyState::CCA_BUSY;
     }
@@ -232,28 +286,32 @@
 WifiPhyStateHelper::LogPreviousIdleAndCcaBusyStates()
 {
     NS_LOG_FUNCTION(this);
-    Time now = Simulator::Now();
+    const auto now = Simulator::Now();
     WifiPhyState state = GetState();
     if (state == WifiPhyState::CCA_BUSY)
     {
-        Time ccaStart = std::max({m_endRx, m_endTx, m_startCcaBusy, m_endSwitching});
+        m_endCcaBusy = now;
+        const auto ccaStart =
+            std::max({m_endRx, m_endTx, m_startCcaBusy, m_endSwitching, m_endSleep, m_endOff});
         m_stateLogger(ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
     }
     else if (state == WifiPhyState::IDLE)
     {
-        Time idleStart = std::max({m_endCcaBusy, m_endRx, m_endTx, m_endSwitching});
+        m_endIdle = now;
+        const auto endAllButCcaBusy =
+            std::max({m_endRx, m_endTx, m_endSwitching, m_endSleep, m_endOff});
+        const auto idleStart = std::max(m_endCcaBusy, endAllButCcaBusy);
         NS_ASSERT(idleStart <= now);
-        if (m_endCcaBusy > m_endRx && m_endCcaBusy > m_endSwitching && m_endCcaBusy > m_endTx)
+        if (m_endCcaBusy > endAllButCcaBusy)
         {
-            Time ccaBusyStart = std::max({m_endTx, m_endRx, m_startCcaBusy, m_endSwitching});
-            Time ccaBusyDuration = idleStart - ccaBusyStart;
-            if (ccaBusyDuration.IsStrictlyPositive())
+            const auto ccaBusyStart = std::max(m_startCcaBusy, endAllButCcaBusy);
+            if (const auto ccaBusyDuration = idleStart - ccaBusyStart;
+                ccaBusyDuration.IsStrictlyPositive())
             {
                 m_stateLogger(ccaBusyStart, ccaBusyDuration, WifiPhyState::CCA_BUSY);
             }
         }
-        Time idleDuration = now - idleStart;
-        if (idleDuration.IsStrictlyPositive())
+        if (const auto idleDuration = now - idleStart; idleDuration.IsStrictlyPositive())
         {
             m_stateLogger(idleStart, idleDuration, WifiPhyState::IDLE);
         }
@@ -412,6 +470,16 @@
 }
 
 void
+WifiPhyStateHelper::NotifyRxPpduOutcome(Ptr<const WifiPpdu> ppdu,
+                                        RxSignalInfo rxSignalInfo,
+                                        const WifiTxVector& txVector,
+                                        uint16_t staId,
+                                        const std::vector<bool>& statusPerMpdu)
+{
+    m_rxOutcomeTrace(ppdu, rxSignalInfo, txVector, statusPerMpdu);
+}
+
+void
 WifiPhyStateHelper::SwitchFromRxEndOk()
 {
     NS_LOG_FUNCTION(this);
@@ -500,6 +568,7 @@
     m_stateLogger(m_startSleep, now - m_startSleep, WifiPhyState::SLEEP);
     m_previousStateChangeTime = now;
     m_sleeping = false;
+    m_endSleep = now;
     NotifyListeners(&WifiPhyListener::NotifyWakeup);
 }
 
@@ -556,6 +625,7 @@
     }
     m_previousStateChangeTime = now;
     m_isOff = true;
+    m_startOff = now;
     NotifyListeners(&WifiPhyListener::NotifyOff);
     NS_ASSERT(IsStateOff());
 }
@@ -568,6 +638,7 @@
     Time now = Simulator::Now();
     m_previousStateChangeTime = now;
     m_isOff = false;
+    m_endOff = now;
     NotifyListeners(&WifiPhyListener::NotifyOn);
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-phy-state-helper.h ns-3.42/src/wifi/model/wifi-phy-state-helper.h
--- ns-3.41/src/wifi/model/wifi-phy-state-helper.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-phy-state-helper.h	2024-05-29 15:29:47.212073800 -0700
@@ -20,6 +20,7 @@
 #ifndef WIFI_PHY_STATE_HELPER_H
 #define WIFI_PHY_STATE_HELPER_H
 
+#include "phy-entity.h"
 #include "wifi-phy-common.h"
 #include "wifi-phy-state.h"
 #include "wifi-ppdu.h"
@@ -29,6 +30,7 @@
 #include "ns3/object.h"
 #include "ns3/traced-callback.h"
 
+#include <algorithm>
 #include <list>
 #include <memory>
 #include <vector>
@@ -170,6 +172,12 @@
     Time GetLastRxEndTime() const;
 
     /**
+     * \param states a set of PHY states
+     * \return the last time the PHY has been in any of the given states
+     */
+    Time GetLastTime(std::initializer_list<WifiPhyState> states) const;
+
+    /**
      * Switch state to TX for the given duration.
      *
      * \param txDuration the duration of the PPDU to transmit
@@ -224,6 +232,21 @@
      * \param snr the SNR of the received PSDU in linear scale
      */
     void NotifyRxPsduFailed(Ptr<const WifiPsdu> psdu, double snr);
+
+    /**
+     * Handle the outcome of a reception of a PPDU.
+     *
+     * \param ppdu the received PPDU
+     * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
+     * \param txVector TXVECTOR of the PSDU
+     * \param staId the station ID of the PSDU (only used for MU)
+     * \param statusPerMpdu reception status per MPDU
+     */
+    void NotifyRxPpduOutcome(Ptr<const WifiPpdu> ppdu,
+                             RxSignalInfo rxSignalInfo,
+                             const WifiTxVector& txVector,
+                             uint16_t staId,
+                             const std::vector<bool>& statusPerMpdu);
     /**
      * Switch from RX after the reception was successful.
      */
@@ -291,6 +314,22 @@
                                        WifiPreamble preamble);
 
     /**
+     * TracedCallback signature for the outcome of a received packet.
+     *
+     * \param [in] psdu The received PSDU (Physical Layer Service Data Unit).
+     * \param [in] signalInfo Information about the received signal, including its power and other
+     * characteristics.
+     * \param [in] txVector The transmission vector used for the packet, detailing
+     * the transmission parameters.
+     * \param [in] outcomes A vector of boolean values indicating the
+     * success or failure of receiving individual MPDUs within the PSDU.
+     */
+    typedef void (*RxOutcomeTracedCallback)(Ptr<const WifiPsdu> psdu,
+                                            RxSignalInfo signalInfo,
+                                            const WifiTxVector& txVector,
+                                            const std::vector<bool>& outcomes);
+
+    /**
      * TracedCallback signature for receive end error event.
      *
      * \param [in] packet       The received packet.
@@ -352,16 +391,22 @@
     Time m_endRx;                   ///< end receive
     Time m_endCcaBusy;              ///< end CCA busy
     Time m_endSwitching;            ///< end switching
+    Time m_endSleep;                ///< end sleep
+    Time m_endOff;                  ///< end off
+    Time m_endIdle;                 ///< end idle
     Time m_startTx;                 ///< start transmit
     Time m_startRx;                 ///< start receive
     Time m_startCcaBusy;            ///< start CCA busy
     Time m_startSwitching;          ///< start switching
     Time m_startSleep;              ///< start sleep
+    Time m_startOff;                ///< start off
     Time m_previousStateChangeTime; ///< previous state change time
 
     Listeners m_listeners; ///< listeners
     TracedCallback<Ptr<const Packet>, double, WifiMode, WifiPreamble>
-        m_rxOkTrace;                                          ///< receive OK trace callback
+        m_rxOkTrace; ///< receive OK trace callback
+    TracedCallback<Ptr<const WifiPpdu>, RxSignalInfo, const WifiTxVector&, const std::vector<bool>&>
+        m_rxOutcomeTrace;                                     ///< receive OK trace callback
     TracedCallback<Ptr<const Packet>, double> m_rxErrorTrace; ///< receive error trace callback
     TracedCallback<Ptr<const Packet>, WifiMode, WifiPreamble, uint8_t>
         m_txTrace;                     ///< transmit trace callback
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-protection.cc ns-3.42/src/wifi/model/wifi-protection.cc
--- ns-3.41/src/wifi/model/wifi-protection.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-protection.cc	2024-05-29 15:29:47.212073800 -0700
@@ -29,8 +29,7 @@
  */
 
 WifiProtection::WifiProtection(Method m)
-    : method(m),
-      protectionTime(Time::Min()) // uninitialized
+    : method(m)
 {
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-protection.h ns-3.42/src/wifi/model/wifi-protection.h
--- ns-3.41/src/wifi/model/wifi-protection.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-protection.h	2024-05-29 15:29:47.212073800 -0700
@@ -26,6 +26,7 @@
 #include "ns3/nstime.h"
 
 #include <memory>
+#include <optional>
 
 namespace ns3
 {
@@ -70,8 +71,8 @@
      */
     virtual void Print(std::ostream& os) const = 0;
 
-    const Method method; //!< protection method
-    Time protectionTime; //!< time required by the protection method
+    const Method method;                //!< protection method
+    std::optional<Time> protectionTime; //!< time required by the protection method
 };
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-psdu.cc ns-3.42/src/wifi/model/wifi-psdu.cc
--- ns-3.41/src/wifi/model/wifi-psdu.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-psdu.cc	2024-05-29 15:29:47.212073800 -0700
@@ -192,7 +192,7 @@
 WifiPsdu::GetAckPolicyForTid(uint8_t tid) const
 {
     NS_LOG_FUNCTION(this << +tid);
-    WifiMacHeader::QosAckPolicy policy;
+    WifiMacHeader::QosAckPolicy policy{WifiMacHeader::NORMAL_ACK};
     auto it = m_mpduList.begin();
     bool found = false;
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-radio-energy-model.cc ns-3.42/src/wifi/model/wifi-radio-energy-model.cc
--- ns-3.41/src/wifi/model/wifi-radio-energy-model.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-radio-energy-model.cc	2024-05-29 15:29:47.212073800 -0700
@@ -114,7 +114,7 @@
 }
 
 void
-WifiRadioEnergyModel::SetEnergySource(const Ptr<EnergySource> source)
+WifiRadioEnergyModel::SetEnergySource(const Ptr<energy::EnergySource> source)
 {
     NS_LOG_FUNCTION(this << source);
     NS_ASSERT(source);
@@ -124,7 +124,7 @@
     m_switchToOffEvent = Simulator::Schedule(durationToOff,
                                              &WifiRadioEnergyModel::ChangeState,
                                              this,
-                                             WifiPhyState::OFF);
+                                             static_cast<int>(WifiPhyState::OFF));
 }
 
 double
@@ -274,7 +274,7 @@
 }
 
 Time
-WifiRadioEnergyModel::GetMaximumTimeInState(int state) const
+WifiRadioEnergyModel::GetMaximumTimeInState(WifiPhyState state) const
 {
     if (state == WifiPhyState::OFF)
     {
@@ -289,25 +289,26 @@
 void
 WifiRadioEnergyModel::ChangeState(int newState)
 {
-    NS_LOG_FUNCTION(this << newState);
+    WifiPhyState newPhyState{newState};
+    NS_LOG_FUNCTION(this << newPhyState);
 
     m_nPendingChangeState++;
 
-    if (m_nPendingChangeState > 1 && newState == WifiPhyState::OFF)
+    if (m_nPendingChangeState > 1 && newPhyState == WifiPhyState::OFF)
     {
-        SetWifiRadioState((WifiPhyState)newState);
+        SetWifiRadioState(newPhyState);
         m_nPendingChangeState--;
         return;
     }
 
-    if (newState != WifiPhyState::OFF)
+    if (newPhyState != WifiPhyState::OFF)
     {
         m_switchToOffEvent.Cancel();
-        Time durationToOff = GetMaximumTimeInState(newState);
+        Time durationToOff = GetMaximumTimeInState(newPhyState);
         m_switchToOffEvent = Simulator::Schedule(durationToOff,
                                                  &WifiRadioEnergyModel::ChangeState,
                                                  this,
-                                                 WifiPhyState::OFF);
+                                                 static_cast<int>(WifiPhyState::OFF));
     }
 
     Time duration = Simulator::Now() - m_lastUpdateTime;
@@ -337,7 +338,7 @@
     if (m_nPendingChangeState <= 1 && m_currentState != WifiPhyState::OFF)
     {
         // update current state & last update time stamp
-        SetWifiRadioState((WifiPhyState)newState);
+        SetWifiRadioState(newPhyState);
 
         // some debug message
         NS_LOG_DEBUG("WifiRadioEnergyModel:Total energy consumption is " << m_totalEnergyConsumption
@@ -383,7 +384,7 @@
         m_switchToOffEvent = Simulator::Schedule(durationToOff,
                                                  &WifiRadioEnergyModel::ChangeState,
                                                  this,
-                                                 WifiPhyState::OFF);
+                                                 static_cast<int>(WifiPhyState::OFF));
     }
 }
 
@@ -407,7 +408,7 @@
 }
 
 double
-WifiRadioEnergyModel::GetStateA(int state) const
+WifiRadioEnergyModel::GetStateA(WifiPhyState state) const
 {
     switch (state)
     {
@@ -485,7 +486,7 @@
 
 void
 WifiRadioEnergyModelPhyListener::SetChangeStateCallback(
-    DeviceEnergyModel::ChangeStateCallback callback)
+    energy::DeviceEnergyModel::ChangeStateCallback callback)
 {
     NS_LOG_FUNCTION(this << &callback);
     NS_ASSERT(!callback.IsNull());
@@ -508,7 +509,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::RX);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::RX));
     m_switchToIdleEvent.Cancel();
 }
 
@@ -520,7 +521,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::IDLE);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::IDLE));
 }
 
 void
@@ -531,7 +532,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::IDLE);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::IDLE));
 }
 
 void
@@ -547,7 +548,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::TX);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::TX));
     // schedule changing state back to IDLE after TX duration
     m_switchToIdleEvent.Cancel();
     m_switchToIdleEvent =
@@ -564,7 +565,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::CCA_BUSY);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::CCA_BUSY));
     // schedule changing state back to IDLE after CCA_BUSY duration
     m_switchToIdleEvent.Cancel();
     m_switchToIdleEvent =
@@ -579,7 +580,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::SWITCHING);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::SWITCHING));
     // schedule changing state back to IDLE after CCA_BUSY duration
     m_switchToIdleEvent.Cancel();
     m_switchToIdleEvent =
@@ -594,7 +595,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::SLEEP);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::SLEEP));
     m_switchToIdleEvent.Cancel();
 }
 
@@ -606,7 +607,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::IDLE);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::IDLE));
 }
 
 void
@@ -617,7 +618,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::OFF);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::OFF));
     m_switchToIdleEvent.Cancel();
 }
 
@@ -629,7 +630,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::IDLE);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::IDLE));
 }
 
 void
@@ -640,7 +641,7 @@
     {
         NS_FATAL_ERROR("WifiRadioEnergyModelPhyListener:Change state callback not set!");
     }
-    m_changeStateCallback(WifiPhyState::IDLE);
+    m_changeStateCallback(static_cast<int>(WifiPhyState::IDLE));
 }
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-radio-energy-model.h ns-3.42/src/wifi/model/wifi-radio-energy-model.h
--- ns-3.41/src/wifi/model/wifi-radio-energy-model.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-radio-energy-model.h	2024-05-29 15:29:47.212073800 -0700
@@ -56,7 +56,7 @@
      *
      * \param callback Change state callback.
      */
-    void SetChangeStateCallback(DeviceEnergyModel::ChangeStateCallback callback);
+    void SetChangeStateCallback(energy::DeviceEnergyModel::ChangeStateCallback callback);
 
     /**
      * \brief Sets the update TX current callback.
@@ -88,7 +88,7 @@
      * Change state callback used to notify the WifiRadioEnergyModel of a state
      * change.
      */
-    DeviceEnergyModel::ChangeStateCallback m_changeStateCallback;
+    energy::DeviceEnergyModel::ChangeStateCallback m_changeStateCallback;
 
     /**
      * Callback used to update the TX current stored in WifiRadioEnergyModel based on
@@ -148,7 +148,7 @@
  * transmit power can also be achieved through a wifi TX current model.
  *
  */
-class WifiRadioEnergyModel : public DeviceEnergyModel
+class WifiRadioEnergyModel : public energy::DeviceEnergyModel
 {
   public:
     /**
@@ -176,7 +176,7 @@
      *
      * Implements DeviceEnergyModel::SetEnergySource.
      */
-    void SetEnergySource(const Ptr<EnergySource> source) override;
+    void SetEnergySource(const Ptr<energy::EnergySource> source) override;
 
     /**
      * \returns Total energy consumption of the wifi device in watts.
@@ -305,7 +305,7 @@
      *
      * \returns the time the radio can stay in that state based on the remaining energy.
      */
-    Time GetMaximumTimeInState(int state) const;
+    Time GetMaximumTimeInState(WifiPhyState state) const;
 
     /**
      * \brief Handles energy depletion.
@@ -340,7 +340,7 @@
      * \param state the wifi state
      * \returns draw of device in Amperes, at given state.
      */
-    double GetStateA(int state) const;
+    double GetStateA(WifiPhyState state) const;
 
     /**
      * \returns Current draw of device in Amperes, at current state.
@@ -357,7 +357,7 @@
      */
     void SetWifiRadioState(const WifiPhyState state);
 
-    Ptr<EnergySource> m_source; ///< energy source
+    Ptr<energy::EnergySource> m_source; ///< energy source
 
     // Member variables for current draw in different radio modes.
     double m_txCurrentA;                      ///< transmit current in Amperes
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-remote-station-manager.cc ns-3.42/src/wifi/model/wifi-remote-station-manager.cc
--- ns-3.41/src/wifi/model/wifi-remote-station-manager.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-remote-station-manager.cc	2024-05-29 15:29:47.212073800 -0700
@@ -26,6 +26,7 @@
 #include "wifi-mpdu.h"
 #include "wifi-net-device.h"
 #include "wifi-phy.h"
+#include "wifi-tx-parameters.h"
 
 #include "ns3/boolean.h"
 #include "ns3/eht-configuration.h"
@@ -74,6 +75,13 @@
                           UintegerValue(4692480),
                           MakeUintegerAccessor(&WifiRemoteStationManager::SetRtsCtsThreshold),
                           MakeUintegerChecker<uint32_t>(0, 4692480))
+            .AddAttribute("RtsCtsTxDurationThresh",
+                          "If this threshold is a strictly positive value and the TX duration of "
+                          "the PSDU is greater than or equal to this threshold, we use an RTS/CTS "
+                          "handshake before sending the data frame.",
+                          TimeValue(Time{0}),
+                          MakeTimeAccessor(&WifiRemoteStationManager::m_rtsCtsTxDurationThresh),
+                          MakeTimeChecker())
             .AddAttribute(
                 "FragmentationThreshold",
                 "If the size of the PSDU is bigger than this value, we fragment it such that the "
@@ -245,14 +253,16 @@
 bool
 WifiRemoteStationManager::GetHtSupported() const
 {
-    return bool(m_wifiPhy->GetDevice()->GetHtConfiguration());
+    return (m_wifiPhy->GetDevice()->GetHtConfiguration() &&
+            m_wifiPhy->GetPhyBand() != WIFI_PHY_BAND_6GHZ);
 }
 
 bool
 WifiRemoteStationManager::GetVhtSupported() const
 {
     return (m_wifiPhy->GetDevice()->GetVhtConfiguration() &&
-            m_wifiPhy->GetPhyBand() != WIFI_PHY_BAND_2_4GHZ);
+            m_wifiPhy->GetPhyBand() != WIFI_PHY_BAND_2_4GHZ &&
+            m_wifiPhy->GetPhyBand() != WIFI_PHY_BAND_6GHZ);
 }
 
 bool
@@ -270,11 +280,8 @@
 bool
 WifiRemoteStationManager::GetLdpcSupported() const
 {
-    if (GetHtSupported())
+    if (auto htConfiguration = m_wifiPhy->GetDevice()->GetHtConfiguration())
     {
-        Ptr<HtConfiguration> htConfiguration = m_wifiPhy->GetDevice()->GetHtConfiguration();
-        NS_ASSERT(htConfiguration); // If HT is supported, we should have a HT configuration
-                                    // attached
         return htConfiguration->GetLdpcSupported();
     }
     return false;
@@ -283,15 +290,9 @@
 bool
 WifiRemoteStationManager::GetShortGuardIntervalSupported() const
 {
-    if (GetHtSupported())
+    if (auto htConfiguration = m_wifiPhy->GetDevice()->GetHtConfiguration())
     {
-        Ptr<HtConfiguration> htConfiguration = m_wifiPhy->GetDevice()->GetHtConfiguration();
-        NS_ASSERT(htConfiguration); // If HT is supported, we should have a HT configuration
-                                    // attached
-        if (htConfiguration->GetShortGuardIntervalSupported())
-        {
-            return true;
-        }
+        return htConfiguration->GetShortGuardIntervalSupported();
     }
     return false;
 }
@@ -863,7 +864,7 @@
             found = true;
         }
     }
-    if (GetHtSupported())
+    if (m_wifiPhy->GetDevice()->GetHtConfiguration())
     {
         if (!found)
         {
@@ -932,7 +933,7 @@
             found = true;
         }
     }
-    if (GetHtSupported())
+    if (m_wifiPhy->GetDevice()->GetHtConfiguration())
     {
         for (const auto& thismode : m_wifiPhy->GetMcsList())
         {
@@ -1119,12 +1120,11 @@
 }
 
 bool
-WifiRemoteStationManager::NeedRts(const WifiMacHeader& header, uint32_t size)
+WifiRemoteStationManager::NeedRts(const WifiMacHeader& header, const WifiTxParameters& txParams)
 {
-    NS_LOG_FUNCTION(this << header << size);
-    Mac48Address address = header.GetAddr1();
-    WifiTxVector txVector = GetDataTxVector(header, m_wifiPhy->GetChannelWidth());
-    const auto modulationClass = txVector.GetModulationClass();
+    NS_LOG_FUNCTION(this << header << &txParams);
+    auto address = header.GetAddr1();
+    const auto modulationClass = txParams.m_txVector.GetModulationClass();
     if (address.IsGroup())
     {
         return false;
@@ -1146,7 +1146,11 @@
         NS_LOG_DEBUG("WifiRemoteStationManager::NeedRTS returning true to protect non-HT stations");
         return true;
     }
-    bool normally = (size > m_rtsCtsThreshold);
+    NS_ASSERT(txParams.m_txDuration.has_value());
+    auto size = txParams.GetSize(header.GetAddr1());
+    bool normally =
+        (size > m_rtsCtsThreshold) || (m_rtsCtsTxDurationThresh.IsStrictlyPositive() &&
+                                       *txParams.m_txDuration >= m_rtsCtsTxDurationThresh);
     return DoNeedRts(Lookup(address), size, normally);
 }
 
@@ -1188,7 +1192,7 @@
                 return false;
             }
         }
-        if (GetHtSupported())
+        if (m_wifiPhy->GetDevice()->GetHtConfiguration())
         {
             // search for the BSS Basic MCS set, if the used mode is in the basic set then there is
             // no need for CTS To Self
@@ -1590,6 +1594,18 @@
 }
 
 void
+WifiRemoteStationManager::AddStationHe6GhzCapabilities(
+    const Mac48Address& from,
+    const He6GhzBandCapabilities& he6GhzCapabilities)
+{
+    // Used by all stations to record HE 6GHz band capabilities of remote stations
+    NS_LOG_FUNCTION(this << from << he6GhzCapabilities);
+    auto state = LookupState(from);
+    state->m_he6GhzBandCapabilities = Create<const He6GhzBandCapabilities>(he6GhzCapabilities);
+    SetQosSupport(from, true);
+}
+
+void
 WifiRemoteStationManager::AddStationEhtCapabilities(Mac48Address from,
                                                     EhtCapabilities ehtCapabilities)
 {
@@ -1642,6 +1658,12 @@
     return LookupState(from)->m_heCapabilities;
 }
 
+Ptr<const He6GhzBandCapabilities>
+WifiRemoteStationManager::GetStationHe6GhzCapabilities(const Mac48Address& from) const
+{
+    return LookupState(from)->m_he6GhzBandCapabilities;
+}
+
 Ptr<const EhtCapabilities>
 WifiRemoteStationManager::GetStationEhtCapabilities(Mac48Address from)
 {
@@ -1712,7 +1734,8 @@
 {
     NS_LOG_FUNCTION(this << st);
 
-    if (!GetHtSupported() || !GetHtSupported(st))
+    if ((!m_wifiPhy->GetDevice()->GetHtConfiguration()) ||
+        (!GetHtSupported(st) && !GetStationHe6GhzCapabilities(st->m_state->m_address)))
     {
         return GetDefaultMode();
     }
@@ -1983,10 +2006,14 @@
 uint8_t
 WifiRemoteStationManager::GetNumberOfSupportedStreams(const WifiRemoteStation* station) const
 {
-    Ptr<const HtCapabilities> htCapabilities = station->m_state->m_htCapabilities;
+    const auto htCapabilities = station->m_state->m_htCapabilities;
 
     if (!htCapabilities)
     {
+        if (const auto heCapabilities = station->m_state->m_heCapabilities)
+        {
+            return heCapabilities->GetHighestNssSupported();
+        }
         return 1;
     }
     return htCapabilities->GetRxHighestSupportedAntennas();
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-remote-station-manager.h ns-3.42/src/wifi/model/wifi-remote-station-manager.h
--- ns-3.41/src/wifi/model/wifi-remote-station-manager.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-remote-station-manager.h	2024-05-29 15:29:47.212073800 -0700
@@ -27,6 +27,7 @@
 
 #include "ns3/data-rate.h"
 #include "ns3/eht-capabilities.h"
+#include "ns3/he-6ghz-band-capabilities.h"
 #include "ns3/he-capabilities.h"
 #include "ns3/ht-capabilities.h"
 #include "ns3/mac48-address.h"
@@ -49,6 +50,7 @@
 class Packet;
 class WifiMpdu;
 class WifiTxVector;
+class WifiTxParameters;
 
 struct WifiRemoteStationState;
 struct RxSignalInfo;
@@ -111,6 +113,8 @@
     Ptr<const HtCapabilities> m_htCapabilities;   //!< remote station HT capabilities
     Ptr<const VhtCapabilities> m_vhtCapabilities; //!< remote station VHT capabilities
     Ptr<const HeCapabilities> m_heCapabilities;   //!< remote station HE capabilities
+    Ptr<const He6GhzBandCapabilities>
+        m_he6GhzBandCapabilities;                 //!< remote station HE 6GHz band capabilities
     Ptr<const EhtCapabilities> m_ehtCapabilities; //!< remote station EHT capabilities
     /// remote station Multi-Link Element Common Info
     std::shared_ptr<CommonInfoBasicMle> m_mleCommonInfo;
@@ -261,6 +265,14 @@
      */
     void AddStationHeCapabilities(Mac48Address from, HeCapabilities heCapabilities);
     /**
+     * Records HE 6 GHz Band Capabilities of a remote station
+     *
+     * \param from the address of the remote station
+     * \param he6GhzCapabilities the HE 6 GHz Band Capabilities of the remote station
+     */
+    void AddStationHe6GhzCapabilities(const Mac48Address& from,
+                                      const He6GhzBandCapabilities& he6GhzCapabilities);
+    /**
      * Records EHT capabilities of the remote station.
      *
      * \param from the address of the station being recorded
@@ -298,6 +310,13 @@
      */
     Ptr<const HeCapabilities> GetStationHeCapabilities(Mac48Address from);
     /**
+     * Return the HE 6 GHz Band Capabilities sent by a remote station.
+     *
+     * \param from the address of the remote station
+     * \return the HE 6 GHz Band capabilities sent by the remote station
+     */
+    Ptr<const He6GhzBandCapabilities> GetStationHe6GhzCapabilities(const Mac48Address& from) const;
+    /**
      * Return the EHT capabilities sent by the remote station.
      *
      * \param from the address of the remote station
@@ -317,13 +336,17 @@
     std::optional<std::reference_wrapper<CommonInfoBasicMle::MldCapabilities>>
     GetStationMldCapabilities(const Mac48Address& from);
     /**
-     * Return whether the device has HT capability support enabled.
+     * Return whether the device has HT capability support enabled on the link this manager is
+     * associated with. Note that this means that this function returns false if this is a
+     * 6 GHz link.
      *
      * \return true if HT capability support is enabled, false otherwise
      */
     bool GetHtSupported() const;
     /**
-     * Return whether the device has VHT capability support enabled.
+     * Return whether the device has VHT capability support enabled on the link this manager is
+     * associated with. Note that this means that this function returns false if this is a
+     * 2.4 or 6 GHz link.
      *
      * \return true if VHT capability support is enabled, false otherwise
      */
@@ -955,13 +978,13 @@
     void ReportRxOk(Mac48Address address, RxSignalInfo rxSignalInfo, WifiTxVector txVector);
 
     /**
-     * \param header MAC header
-     * \param size the size of the frame to send in bytes
+     * \param header MAC header of the data frame to send
+     * \param txParams the TX parameters for the data frame to send
      *
      * \return true if we want to use an RTS/CTS handshake for this
      *         frame before sending it, false otherwise.
      */
-    bool NeedRts(const WifiMacHeader& header, uint32_t size);
+    bool NeedRts(const WifiMacHeader& header, const WifiTxParameters& txParams);
     /**
      * Return if we need to do CTS-to-self before sending a DATA.
      *
@@ -1494,6 +1517,7 @@
     uint32_t m_maxSsrc;                //!< Maximum STA short retry count (SSRC)
     uint32_t m_maxSlrc;                //!< Maximum STA long retry count (SLRC)
     uint32_t m_rtsCtsThreshold;        //!< Threshold for RTS/CTS
+    Time m_rtsCtsTxDurationThresh;     //!< TX duration threshold for RTS/CTS
     uint32_t m_fragmentationThreshold; //!< Current threshold for fragmentation
     uint8_t m_defaultTxPowerLevel;     //!< Default transmission power level
     WifiMode m_nonUnicastMode;         //!< Transmission mode for non-unicast Data frames
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-spectrum-value-helper.cc ns-3.42/src/wifi/model/wifi-spectrum-value-helper.cc
--- ns-3.41/src/wifi/model/wifi-spectrum-value-helper.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/wifi-spectrum-value-helper.cc	2024-05-29 15:29:47.212073800 -0700
@@ -0,0 +1,838 @@
+/*
+ * Copyright (c) 2009 CTTC
+ * Copyright (c) 2010 TELEMATICS LAB, DEE - Politecnico di Bari
+ * Copyright (c) 2017 Orange Labs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Nicola Baldo <nbaldo@cttc.es>
+ *          Giuseppe Piro  <g.piro@poliba.it>
+ *          Rediet <getachew.redieteab@orange.com>
+ */
+
+#include "wifi-spectrum-value-helper.h"
+
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/log.h"
+
+#include <cmath>
+#include <map>
+#include <sstream>
+
+namespace ns3
+{
+
+NS_LOG_COMPONENT_DEFINE("WifiSpectrumValueHelper");
+
+///< Wifi Spectrum Model structure
+struct WifiSpectrumModelId
+{
+    uint32_t m_centerFrequency; ///< center frequency (in MHz)
+    uint16_t m_channelWidth;    ///< channel width (in MHz)
+    uint32_t m_carrierSpacing;  ///< carrier spacing (in Hz)
+    uint16_t m_guardBandwidth;  ///< guard band width (in MHz)
+};
+
+/**
+ * Less than operator
+ * \param a the first wifi spectrum to compare
+ * \param b the second wifi spectrum to compare
+ * \returns true if the first spectrum is less than the second spectrum
+ */
+bool
+operator<(const WifiSpectrumModelId& a, const WifiSpectrumModelId& b)
+{
+    return (
+        (a.m_centerFrequency < b.m_centerFrequency) ||
+        ((a.m_centerFrequency == b.m_centerFrequency) && (a.m_channelWidth < b.m_channelWidth)) ||
+        ((a.m_centerFrequency == b.m_centerFrequency) && (a.m_channelWidth == b.m_channelWidth) &&
+         (a.m_carrierSpacing < b.m_carrierSpacing)) // to cover coexistence of 11ax with legacy case
+        || ((a.m_centerFrequency == b.m_centerFrequency) &&
+            (a.m_channelWidth == b.m_channelWidth) && (a.m_carrierSpacing == b.m_carrierSpacing) &&
+            (a.m_guardBandwidth <
+             b.m_guardBandwidth))); // to cover 2.4 GHz case, where DSSS coexists with OFDM
+}
+
+static std::map<WifiSpectrumModelId, Ptr<SpectrumModel>>
+    g_wifiSpectrumModelMap; ///< static initializer for the class
+
+Ptr<SpectrumModel>
+WifiSpectrumValueHelper::GetSpectrumModel(uint32_t centerFrequency,
+                                          uint16_t channelWidth,
+                                          uint32_t carrierSpacing,
+                                          uint16_t guardBandwidth)
+{
+    NS_LOG_FUNCTION(centerFrequency << channelWidth << carrierSpacing << guardBandwidth);
+    Ptr<SpectrumModel> ret;
+    WifiSpectrumModelId key{centerFrequency, channelWidth, carrierSpacing, guardBandwidth};
+    auto it = g_wifiSpectrumModelMap.find(key);
+    if (it != g_wifiSpectrumModelMap.end())
+    {
+        ret = it->second;
+    }
+    else
+    {
+        Bands bands;
+        double centerFrequencyHz = centerFrequency * 1e6;
+        double bandwidth = (channelWidth + (2.0 * guardBandwidth)) * 1e6;
+        // For OFDM, the center subcarrier is null (at center frequency)
+        auto numBands = static_cast<uint32_t>((bandwidth / carrierSpacing) + 0.5);
+        NS_ASSERT(numBands > 0);
+        if (numBands % 2 == 0)
+        {
+            // round up to the nearest odd number of subbands so that bands
+            // are symmetric around center frequency
+            numBands += 1;
+        }
+        NS_ASSERT_MSG(numBands % 2 == 1, "Number of bands should be odd");
+        NS_LOG_DEBUG("Num bands " << numBands << " band bandwidth " << carrierSpacing);
+        // lay down numBands/2 bands symmetrically around center frequency
+        // and place an additional band at center frequency
+        double startingFrequencyHz =
+            centerFrequencyHz - (numBands / 2 * carrierSpacing) - carrierSpacing / 2;
+        for (size_t i = 0; i < numBands; i++)
+        {
+            BandInfo info;
+            double f = startingFrequencyHz + (i * carrierSpacing);
+            info.fl = f;
+            f += carrierSpacing / 2;
+            info.fc = f;
+            f += carrierSpacing / 2;
+            info.fh = f;
+            NS_LOG_DEBUG("creating band " << i << " (" << info.fl << ":" << info.fc << ":"
+                                          << info.fh << ")");
+            bands.push_back(info);
+        }
+        ret = Create<SpectrumModel>(std::move(bands));
+        g_wifiSpectrumModelMap.insert(std::pair<WifiSpectrumModelId, Ptr<SpectrumModel>>(key, ret));
+    }
+    NS_LOG_LOGIC("returning SpectrumModel::GetUid () == " << ret->GetUid());
+    return ret;
+}
+
+// Power allocated to 71 center subbands out of 135 total subbands in the band
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateDsssTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                          double txPowerW,
+                                                          uint16_t guardBandwidth)
+{
+    NS_LOG_FUNCTION(centerFrequency << txPowerW << +guardBandwidth);
+    uint16_t channelWidth = 22; // DSSS channels are 22 MHz wide
+    uint32_t carrierSpacing = 312500;
+    Ptr<SpectrumValue> c = Create<SpectrumValue>(
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
+    auto vit = c->ValuesBegin();
+    auto bit = c->ConstBandsBegin();
+    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
+    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    NS_ASSERT(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1));
+    // Evenly spread power across 22 MHz
+    double txPowerPerBand = txPowerW / nAllocatedBands;
+    for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++, bit++)
+    {
+        if ((i >= (nGuardBands / 2)) && (i <= ((nGuardBands / 2) + nAllocatedBands - 1)))
+        {
+            *vit = txPowerPerBand / (bit->fh - bit->fl);
+        }
+    }
+    return c;
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                          uint16_t channelWidth,
+                                                          double txPowerW,
+                                                          uint16_t guardBandwidth,
+                                                          double minInnerBandDbr,
+                                                          double minOuterBandDbr,
+                                                          double lowestPointDbr)
+{
+    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
+                                    << minOuterBandDbr << lowestPointDbr);
+    uint32_t carrierSpacing = 0;
+    uint32_t innerSlopeWidth = 0;
+    switch (channelWidth)
+    {
+    case 20:
+        carrierSpacing = 312500;
+        innerSlopeWidth = static_cast<uint32_t>((2e6 / carrierSpacing) + 0.5); // [-11;-9] & [9;11]
+        break;
+    case 10:
+        carrierSpacing = 156250;
+        innerSlopeWidth =
+            static_cast<uint32_t>((1e6 / carrierSpacing) + 0.5); // [-5.5;-4.5] & [4.5;5.5]
+        break;
+    case 5:
+        carrierSpacing = 78125;
+        innerSlopeWidth =
+            static_cast<uint32_t>((5e5 / carrierSpacing) + 0.5); // [-2.75;-2.5] & [2.5;2.75]
+        break;
+    default:
+        NS_FATAL_ERROR("Channel width " << channelWidth << " should be correctly set.");
+        return nullptr;
+    }
+
+    Ptr<SpectrumValue> c = Create<SpectrumValue>(
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
+    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
+    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
+                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
+    // 52 subcarriers (48 data + 4 pilot)
+    // skip guard band and 6 subbands, then place power in 26 subbands, then
+    // skip the center subband, then place power in 26 subbands, then skip
+    // the final 6 subbands and the guard band.
+    double txPowerPerBandW = txPowerW / 52;
+    NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
+    uint32_t start1 = (nGuardBands / 2) + 6;
+    uint32_t stop1 = start1 + 26 - 1;
+    uint32_t start2 = stop1 + 2;
+    uint32_t stop2 = start2 + 26 - 1;
+
+    // Build transmit spectrum mask
+    std::vector<WifiSpectrumBandIndices> subBands{
+        std::make_pair(start1, stop1),
+        std::make_pair(start2, stop2),
+    };
+    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
+    CreateSpectrumMaskForOfdm(c,
+                              subBands,
+                              maskBand,
+                              txPowerPerBandW,
+                              nGuardBands,
+                              innerSlopeWidth,
+                              minInnerBandDbr,
+                              minOuterBandDbr,
+                              lowestPointDbr);
+    NormalizeSpectrumMask(c, txPowerW);
+    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
+    return c;
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateDuplicated20MhzTxPowerSpectralDensity(
+    uint32_t centerFrequency,
+    uint16_t channelWidth,
+    double txPowerW,
+    uint16_t guardBandwidth,
+    double minInnerBandDbr,
+    double minOuterBandDbr,
+    double lowestPointDbr,
+    const std::vector<bool>& puncturedSubchannels)
+{
+    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
+                                    << minOuterBandDbr << lowestPointDbr);
+    uint32_t carrierSpacing = 312500;
+    Ptr<SpectrumValue> c = Create<SpectrumValue>(
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
+    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
+    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
+                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
+    std::size_t num20MhzBands = channelWidth / 20;
+    std::size_t numAllocatedSubcarriersPer20MHz = 52;
+    NS_ASSERT(puncturedSubchannels.empty() || (puncturedSubchannels.size() == num20MhzBands));
+    double txPowerPerBandW = (txPowerW / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
+    NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
+
+    std::size_t numSubcarriersPer20MHz = (20 * 1e6) / carrierSpacing;
+    std::size_t numUnallocatedSubcarriersPer20MHz =
+        numSubcarriersPer20MHz - numAllocatedSubcarriersPer20MHz;
+    std::vector<WifiSpectrumBandIndices>
+        subBands; // list of data/pilot-containing subBands (sent at 0dBr)
+    subBands.resize(num20MhzBands *
+                    2); // the center subcarrier is skipped, hence 2 subbands per 20 MHz subchannel
+    uint32_t start = (nGuardBands / 2) + (numUnallocatedSubcarriersPer20MHz / 2);
+    uint32_t stop;
+    uint8_t index = 0;
+    for (auto it = subBands.begin(); it != subBands.end();)
+    {
+        if (!puncturedSubchannels.empty() && puncturedSubchannels.at(index++))
+        {
+            // if subchannel is punctured, skip it and go the next one
+            NS_LOG_DEBUG("20 MHz subchannel " << +index << " is punctured");
+            it += 2;
+            continue;
+        }
+        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
+        *it = std::make_pair(start, stop);
+        ++it;
+        start = stop + 2; // skip center subcarrier
+        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
+        *it = std::make_pair(start, stop);
+        ++it;
+        start = stop + numUnallocatedSubcarriersPer20MHz;
+    }
+
+    // Prepare spectrum mask specific variables
+    auto innerSlopeWidth = static_cast<uint32_t>(
+        (2e6 / carrierSpacing) +
+        0.5); // size in number of subcarriers of the 0dBr<->20dBr slope (2MHz for HT/VHT)
+    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
+
+    // Build transmit spectrum mask
+    CreateSpectrumMaskForOfdm(c,
+                              subBands,
+                              maskBand,
+                              txPowerPerBandW,
+                              nGuardBands,
+                              innerSlopeWidth,
+                              minInnerBandDbr,
+                              minOuterBandDbr,
+                              lowestPointDbr);
+    NormalizeSpectrumMask(c, txPowerW);
+    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
+    return c;
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateHtOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                            uint16_t channelWidth,
+                                                            double txPowerW,
+                                                            uint16_t guardBandwidth,
+                                                            double minInnerBandDbr,
+                                                            double minOuterBandDbr,
+                                                            double lowestPointDbr)
+{
+    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
+                                    << minOuterBandDbr << lowestPointDbr);
+    uint32_t carrierSpacing = 312500;
+    Ptr<SpectrumValue> c = Create<SpectrumValue>(
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
+    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
+    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
+                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
+    std::size_t num20MhzBands = channelWidth / 20;
+    std::size_t numAllocatedSubcarriersPer20MHz = 56;
+    double txPowerPerBandW = (txPowerW / numAllocatedSubcarriersPer20MHz) / num20MhzBands;
+    NS_LOG_DEBUG("Power per band " << txPowerPerBandW << "W");
+
+    std::size_t numSubcarriersPer20MHz = (20 * 1e6) / carrierSpacing;
+    std::size_t numUnallocatedSubcarriersPer20MHz =
+        numSubcarriersPer20MHz - numAllocatedSubcarriersPer20MHz;
+    std::vector<WifiSpectrumBandIndices>
+        subBands; // list of data/pilot-containing subBands (sent at 0dBr)
+    subBands.resize(num20MhzBands *
+                    2); // the center subcarrier is skipped, hence 2 subbands per 20 MHz subchannel
+    uint32_t start = (nGuardBands / 2) + (numUnallocatedSubcarriersPer20MHz / 2);
+    uint32_t stop;
+    for (auto it = subBands.begin(); it != subBands.end();)
+    {
+        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
+        *it = std::make_pair(start, stop);
+        ++it;
+        start = stop + 2; // skip center subcarrier
+        stop = start + (numAllocatedSubcarriersPer20MHz / 2) - 1;
+        *it = std::make_pair(start, stop);
+        ++it;
+        start = stop + numUnallocatedSubcarriersPer20MHz;
+    }
+
+    // Prepare spectrum mask specific variables
+    auto innerSlopeWidth = static_cast<uint32_t>(
+        (2e6 / carrierSpacing) +
+        0.5); // size in number of subcarriers of the inner band (2MHz for HT/VHT)
+    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
+
+    // Build transmit spectrum mask
+    CreateSpectrumMaskForOfdm(c,
+                              subBands,
+                              maskBand,
+                              txPowerPerBandW,
+                              nGuardBands,
+                              innerSlopeWidth,
+                              minInnerBandDbr,
+                              minOuterBandDbr,
+                              lowestPointDbr);
+    NormalizeSpectrumMask(c, txPowerW);
+    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
+    return c;
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateHeOfdmTxPowerSpectralDensity(
+    uint32_t centerFrequency,
+    uint16_t channelWidth,
+    double txPowerW,
+    uint16_t guardBandwidth,
+    double minInnerBandDbr,
+    double minOuterBandDbr,
+    double lowestPointDbr,
+    const std::vector<bool>& puncturedSubchannels)
+{
+    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << minInnerBandDbr
+                                    << minOuterBandDbr << lowestPointDbr);
+    uint32_t carrierSpacing = 78125;
+    Ptr<SpectrumValue> c = Create<SpectrumValue>(
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
+    auto nGuardBands = static_cast<uint32_t>(((2 * guardBandwidth * 1e6) / carrierSpacing) + 0.5);
+    auto nAllocatedBands = static_cast<uint32_t>(((channelWidth * 1e6) / carrierSpacing) + 0.5);
+    NS_ASSERT_MSG(c->GetSpectrumModel()->GetNumBands() == (nAllocatedBands + nGuardBands + 1),
+                  "Unexpected number of bands " << c->GetSpectrumModel()->GetNumBands());
+    double txPowerPerBandW = 0.0;
+    uint32_t start1;
+    uint32_t stop1;
+    uint32_t start2;
+    uint32_t stop2;
+    uint32_t start3;
+    uint32_t stop3;
+    uint32_t start4;
+    uint32_t stop4;
+    // Prepare spectrum mask specific variables
+    auto innerSlopeWidth = static_cast<uint32_t>(
+        (1e6 / carrierSpacing) + 0.5); // size in number of subcarriers of the inner band
+    std::vector<WifiSpectrumBandIndices>
+        subBands; // list of data/pilot-containing subBands (sent at 0dBr)
+    WifiSpectrumBandIndices maskBand(0, nAllocatedBands + nGuardBands);
+    switch (channelWidth)
+    {
+    case 20:
+        // 242 subcarriers (234 data + 8 pilot)
+        txPowerPerBandW = txPowerW / 242;
+        innerSlopeWidth =
+            static_cast<uint32_t>((5e5 / carrierSpacing) + 0.5); // [-10.25;-9.75] & [9.75;10.25]
+        // skip the guard band and 6 subbands, then place power in 121 subbands, then
+        // skip 3 DC, then place power in 121 subbands, then skip
+        // the final 5 subbands and the guard band.
+        start1 = (nGuardBands / 2) + 6;
+        stop1 = start1 + 121 - 1;
+        start2 = stop1 + 4;
+        stop2 = start2 + 121 - 1;
+        subBands.emplace_back(start1, stop1);
+        subBands.emplace_back(start2, stop2);
+        break;
+    case 40:
+        // 484 subcarriers (468 data + 16 pilot)
+        txPowerPerBandW = txPowerW / 484;
+        // skip the guard band and 12 subbands, then place power in 242 subbands, then
+        // skip 5 DC, then place power in 242 subbands, then skip
+        // the final 11 subbands and the guard band.
+        start1 = (nGuardBands / 2) + 12;
+        stop1 = start1 + 242 - 1;
+        start2 = stop1 + 6;
+        stop2 = start2 + 242 - 1;
+        subBands.emplace_back(start1, stop1);
+        subBands.emplace_back(start2, stop2);
+        break;
+    case 80:
+        // 996 subcarriers (980 data + 16 pilot)
+        txPowerPerBandW = txPowerW / 996;
+        // skip the guard band and 12 subbands, then place power in 498 subbands, then
+        // skip 5 DC, then place power in 498 subbands, then skip
+        // the final 11 subbands and the guard band.
+        start1 = (nGuardBands / 2) + 12;
+        stop1 = start1 + 498 - 1;
+        start2 = stop1 + 6;
+        stop2 = start2 + 498 - 1;
+        subBands.emplace_back(start1, stop1);
+        subBands.emplace_back(start2, stop2);
+        break;
+    case 160:
+        // 2 x 996 subcarriers (2 x 80 MHZ bands)
+        txPowerPerBandW = txPowerW / (2 * 996);
+        start1 = (nGuardBands / 2) + 12;
+        stop1 = start1 + 498 - 1;
+        start2 = stop1 + 6;
+        stop2 = start2 + 498 - 1;
+        start3 = stop2 + (2 * 12);
+        stop3 = start3 + 498 - 1;
+        start4 = stop3 + 6;
+        stop4 = start4 + 498 - 1;
+        subBands.emplace_back(start1, stop1);
+        subBands.emplace_back(start2, stop2);
+        subBands.emplace_back(start3, stop3);
+        subBands.emplace_back(start4, stop4);
+        break;
+    default:
+        NS_FATAL_ERROR("ChannelWidth " << channelWidth << " unsupported");
+        break;
+    }
+
+    // Create punctured bands
+    auto puncturedSlopeWidth =
+        static_cast<uint32_t>((500e3 / carrierSpacing) +
+                              0.5); // size in number of subcarriers of the punctured slope band
+    std::vector<WifiSpectrumBandIndices> puncturedBands;
+    std::size_t subcarriersPerSuband = (20 * 1e6 / carrierSpacing);
+    uint32_t start = (nGuardBands / 2);
+    uint32_t stop = start + subcarriersPerSuband - 1;
+    for (auto puncturedSubchannel : puncturedSubchannels)
+    {
+        if (puncturedSubchannel)
+        {
+            puncturedBands.emplace_back(start, stop);
+        }
+        start = stop + 1;
+        stop = start + subcarriersPerSuband - 1;
+    }
+
+    // Build transmit spectrum mask
+    CreateSpectrumMaskForOfdm(c,
+                              subBands,
+                              maskBand,
+                              txPowerPerBandW,
+                              nGuardBands,
+                              innerSlopeWidth,
+                              minInnerBandDbr,
+                              minOuterBandDbr,
+                              lowestPointDbr,
+                              puncturedBands,
+                              puncturedSlopeWidth);
+    NormalizeSpectrumMask(c, txPowerW);
+    NS_ASSERT_MSG(std::abs(txPowerW - Integral(*c)) < 1e-6, "Power allocation failed");
+    return c;
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateHeMuOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                              uint16_t channelWidth,
+                                                              double txPowerW,
+                                                              uint16_t guardBandwidth,
+                                                              const WifiSpectrumBandIndices& ru)
+{
+    NS_LOG_FUNCTION(centerFrequency << channelWidth << txPowerW << guardBandwidth << ru.first
+                                    << ru.second);
+    uint32_t carrierSpacing = 78125;
+    Ptr<SpectrumValue> c = Create<SpectrumValue>(
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth));
+
+    // Build spectrum mask
+    auto vit = c->ValuesBegin();
+    auto bit = c->ConstBandsBegin();
+    double txPowerPerBandW = (txPowerW / (ru.second - ru.first + 1)); // FIXME: null subcarriers
+    uint32_t numBands = c->GetSpectrumModel()->GetNumBands();
+    for (size_t i = 0; i < numBands; i++, vit++, bit++)
+    {
+        if (i < ru.first || i > ru.second) // outside the spectrum mask
+        {
+            *vit = 0.0;
+        }
+        else
+        {
+            *vit = (txPowerPerBandW / (bit->fh - bit->fl));
+        }
+    }
+
+    return c;
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateNoisePowerSpectralDensity(uint32_t centerFrequency,
+                                                         uint16_t channelWidth,
+                                                         uint32_t carrierSpacing,
+                                                         double noiseFigure,
+                                                         uint16_t guardBandwidth)
+{
+    Ptr<SpectrumModel> model =
+        GetSpectrumModel(centerFrequency, channelWidth, carrierSpacing, guardBandwidth);
+    return CreateNoisePowerSpectralDensity(noiseFigure, model);
+}
+
+Ptr<SpectrumValue>
+WifiSpectrumValueHelper::CreateNoisePowerSpectralDensity(double noiseFigureDb,
+                                                         Ptr<SpectrumModel> spectrumModel)
+{
+    NS_LOG_FUNCTION(noiseFigureDb << spectrumModel);
+
+    // see "LTE - From theory to practice"
+    // Section 22.4.4.2 Thermal Noise and Receiver Noise Figure
+    const double kT_dBm_Hz = -174.0; // dBm/Hz
+    double kT_W_Hz = DbmToW(kT_dBm_Hz);
+    double noiseFigureLinear = std::pow(10.0, noiseFigureDb / 10.0);
+    double noisePowerSpectralDensity = kT_W_Hz * noiseFigureLinear;
+
+    Ptr<SpectrumValue> noisePsd = Create<SpectrumValue>(spectrumModel);
+    (*noisePsd) = noisePowerSpectralDensity;
+    NS_LOG_INFO("NoisePowerSpectralDensity has integrated power of " << Integral(*noisePsd));
+    return noisePsd;
+}
+
+void
+WifiSpectrumValueHelper::CreateSpectrumMaskForOfdm(
+    Ptr<SpectrumValue> c,
+    const std::vector<WifiSpectrumBandIndices>& allocatedSubBands,
+    const WifiSpectrumBandIndices& maskBand,
+    double txPowerPerBandW,
+    uint32_t nGuardBands,
+    uint32_t innerSlopeWidth,
+    double minInnerBandDbr,
+    double minOuterBandDbr,
+    double lowestPointDbr,
+    const std::vector<WifiSpectrumBandIndices>& puncturedBands,
+    uint32_t puncturedSlopeWidth)
+{
+    NS_LOG_FUNCTION(c << allocatedSubBands.front().first << allocatedSubBands.back().second
+                      << maskBand.first << maskBand.second << txPowerPerBandW << nGuardBands
+                      << innerSlopeWidth << minInnerBandDbr << minOuterBandDbr << lowestPointDbr
+                      << puncturedSlopeWidth);
+    uint32_t numSubBands = allocatedSubBands.size();
+    uint32_t numBands = c->GetSpectrumModel()->GetNumBands();
+    uint32_t numMaskBands = maskBand.second - maskBand.first + 1;
+    NS_ASSERT(numSubBands && numBands && numMaskBands);
+    NS_LOG_LOGIC("Power per band " << txPowerPerBandW << "W");
+
+    // Different power levels
+    double txPowerRefDbm = (10.0 * std::log10(txPowerPerBandW * 1000.0));
+    double txPowerInnerBandMinDbm = txPowerRefDbm + minInnerBandDbr;
+    double txPowerMiddleBandMinDbm = txPowerRefDbm + minOuterBandDbr;
+    double txPowerOuterBandMinDbm =
+        txPowerRefDbm + lowestPointDbr; // TODO also take into account dBm/MHz constraints
+
+    // Different widths (in number of bands)
+    uint32_t outerSlopeWidth =
+        nGuardBands / 4; // nGuardBands is the total left+right guard band. The left/right outer
+                         // part is half of the left/right guard band.
+    uint32_t middleSlopeWidth = outerSlopeWidth - (innerSlopeWidth / 2);
+    WifiSpectrumBandIndices outerBandLeft(
+        maskBand.first, // to handle cases where allocated channel is
+                        // under WifiPhy configured channel width.
+        maskBand.first + outerSlopeWidth - 1);
+    WifiSpectrumBandIndices middleBandLeft(outerBandLeft.second + 1,
+                                           outerBandLeft.second + middleSlopeWidth);
+    WifiSpectrumBandIndices innerBandLeft(
+        allocatedSubBands.front().first - innerSlopeWidth,
+        allocatedSubBands.front().first -
+            1); // better to place slope based on allocated subcarriers
+    WifiSpectrumBandIndices flatJunctionLeft(
+        middleBandLeft.second + 1,
+        innerBandLeft.first - 1); // in order to handle shift due to guard subcarriers
+    WifiSpectrumBandIndices outerBandRight(
+        maskBand.second - outerSlopeWidth + 1,
+        maskBand.second); // start from outer edge to be able to compute flat junction width
+    WifiSpectrumBandIndices middleBandRight(outerBandRight.first - middleSlopeWidth,
+                                            outerBandRight.first - 1);
+    WifiSpectrumBandIndices innerBandRight(allocatedSubBands.back().second + 1,
+                                           allocatedSubBands.back().second + innerSlopeWidth);
+    WifiSpectrumBandIndices flatJunctionRight(innerBandRight.second + 1, middleBandRight.first - 1);
+    std::ostringstream ss;
+    ss << "outerBandLeft=[" << outerBandLeft.first << ";" << outerBandLeft.second << "] "
+       << "middleBandLeft=[" << middleBandLeft.first << ";" << middleBandLeft.second << "] "
+       << "flatJunctionLeft=[" << flatJunctionLeft.first << ";" << flatJunctionLeft.second << "] "
+       << "innerBandLeft=[" << innerBandLeft.first << ";" << innerBandLeft.second << "] "
+       << "subBands=[" << allocatedSubBands.front().first << ";" << allocatedSubBands.back().second
+       << "] ";
+    if (!puncturedBands.empty())
+    {
+        ss << "puncturedBands=[" << puncturedBands.front().first << ";"
+           << puncturedBands.back().second << "] ";
+    }
+    ss << "innerBandRight=[" << innerBandRight.first << ";" << innerBandRight.second << "] "
+       << "flatJunctionRight=[" << flatJunctionRight.first << ";" << flatJunctionRight.second
+       << "] "
+       << "middleBandRight=[" << middleBandRight.first << ";" << middleBandRight.second << "] "
+       << "outerBandRight=[" << outerBandRight.first << ";" << outerBandRight.second << "] ";
+    NS_LOG_DEBUG(ss.str());
+    NS_ASSERT(numMaskBands ==
+              ((allocatedSubBands.back().second - allocatedSubBands.front().first +
+                1) // equivalent to allocatedBand (includes notches and DC)
+               + 2 * (innerSlopeWidth + middleSlopeWidth + outerSlopeWidth) +
+               (flatJunctionLeft.second - flatJunctionLeft.first + 1) // flat junctions
+               + (flatJunctionRight.second - flatJunctionRight.first + 1)));
+
+    // Different slopes
+    double innerSlope = (-1 * minInnerBandDbr) / innerSlopeWidth;
+    double middleSlope = (-1 * (minOuterBandDbr - minInnerBandDbr)) / middleSlopeWidth;
+    double outerSlope = (txPowerMiddleBandMinDbm - txPowerOuterBandMinDbm) / outerSlopeWidth;
+    double puncturedSlope = (-1 * minInnerBandDbr) / puncturedSlopeWidth;
+
+    // Build spectrum mask
+    auto vit = c->ValuesBegin();
+    auto bit = c->ConstBandsBegin();
+    double txPowerW = 0.0;
+    double previousTxPowerW = 0.0;
+    for (size_t i = 0; i < numBands; i++, vit++, bit++)
+    {
+        if (i < maskBand.first || i > maskBand.second) // outside the spectrum mask
+        {
+            txPowerW = 0.0;
+        }
+        else if (i <= outerBandLeft.second &&
+                 i >= outerBandLeft.first) // better to put greater first (less computation)
+        {
+            txPowerW = DbmToW(txPowerOuterBandMinDbm + ((i - outerBandLeft.first) * outerSlope));
+        }
+        else if (i <= middleBandLeft.second && i >= middleBandLeft.first)
+        {
+            txPowerW = DbmToW(txPowerMiddleBandMinDbm + ((i - middleBandLeft.first) * middleSlope));
+        }
+        else if ((i <= flatJunctionLeft.second && i >= flatJunctionLeft.first) ||
+                 (i <= flatJunctionRight.second && i >= flatJunctionRight.first))
+        {
+            txPowerW = DbmToW(txPowerInnerBandMinDbm);
+        }
+        else if (i <= innerBandLeft.second && i >= innerBandLeft.first)
+        {
+            txPowerW =
+                (!puncturedBands.empty() &&
+                 (puncturedBands.front().first <= allocatedSubBands.front().first))
+                    ? DbmToW(txPowerInnerBandMinDbm)
+                    : // first 20 MHz band is punctured
+                    DbmToW(txPowerInnerBandMinDbm + ((i - innerBandLeft.first) * innerSlope));
+        }
+        else if (i <= allocatedSubBands.back().second &&
+                 i >= allocatedSubBands.front().first) // roughly in allocated band
+        {
+            bool insideSubBand = false;
+            for (uint32_t j = 0; !insideSubBand && j < numSubBands;
+                 j++) // continue until inside a sub-band
+            {
+                insideSubBand =
+                    (i <= allocatedSubBands[j].second) && (i >= allocatedSubBands[j].first);
+            }
+            if (insideSubBand)
+            {
+                bool insidePuncturedSubBand = false;
+                uint32_t j = 0;
+                for (; !insidePuncturedSubBand && j < puncturedBands.size();
+                     j++) // continue until inside a punctured sub-band
+                {
+                    insidePuncturedSubBand =
+                        (i <= puncturedBands[j].second) && (i >= puncturedBands[j].first);
+                }
+                if (insidePuncturedSubBand)
+                {
+                    uint32_t startPuncturedSlope =
+                        (puncturedBands[puncturedBands.size() - 1].second -
+                         puncturedSlopeWidth); // only consecutive subchannels can be punctured
+                    if (i >= startPuncturedSlope)
+                    {
+                        txPowerW = DbmToW(txPowerInnerBandMinDbm +
+                                          ((i - startPuncturedSlope) * puncturedSlope));
+                    }
+                    else
+                    {
+                        txPowerW = std::max(DbmToW(txPowerInnerBandMinDbm),
+                                            DbmToW(txPowerRefDbm - ((i - puncturedBands[0].first) *
+                                                                    puncturedSlope)));
+                    }
+                }
+                else
+                {
+                    txPowerW = txPowerPerBandW;
+                }
+            }
+            else
+            {
+                txPowerW = DbmToW(txPowerInnerBandMinDbm);
+            }
+        }
+        else if (i <= innerBandRight.second && i >= innerBandRight.first)
+        {
+            // take min to handle the case where last 20 MHz band is punctured
+            txPowerW = std::min(
+                previousTxPowerW,
+                DbmToW(txPowerRefDbm - ((i - innerBandRight.first + 1) *
+                                        innerSlope))); // +1 so as to be symmetric with left slope
+        }
+        else if (i <= middleBandRight.second && i >= middleBandRight.first)
+        {
+            txPowerW = DbmToW(txPowerInnerBandMinDbm -
+                              ((i - middleBandRight.first + 1) *
+                               middleSlope)); // +1 so as to be symmetric with left slope
+        }
+        else if (i <= outerBandRight.second && i >= outerBandRight.first)
+        {
+            txPowerW = DbmToW(txPowerMiddleBandMinDbm -
+                              ((i - outerBandRight.first + 1) *
+                               outerSlope)); // +1 so as to be symmetric with left slope
+        }
+        else
+        {
+            NS_FATAL_ERROR("Should have handled all cases");
+        }
+        double txPowerDbr = 10 * std::log10(txPowerW / txPowerPerBandW);
+        NS_LOG_LOGIC(uint32_t(i) << " -> " << txPowerDbr);
+        *vit = txPowerW / (bit->fh - bit->fl);
+        previousTxPowerW = txPowerW;
+    }
+    NS_LOG_INFO("Added signal power to subbands " << allocatedSubBands.front().first << "-"
+                                                  << allocatedSubBands.back().second);
+}
+
+void
+WifiSpectrumValueHelper::NormalizeSpectrumMask(Ptr<SpectrumValue> c, double txPowerW)
+{
+    NS_LOG_FUNCTION(c << txPowerW);
+    // Normalize power so that total signal power equals transmit power
+    double currentTxPowerW = Integral(*c);
+    double normalizationRatio = currentTxPowerW / txPowerW;
+    NS_LOG_LOGIC("Current power: " << currentTxPowerW << "W vs expected power: " << txPowerW << "W"
+                                   << " -> ratio (C/E) = " << normalizationRatio);
+    auto vit = c->ValuesBegin();
+    for (size_t i = 0; i < c->GetSpectrumModel()->GetNumBands(); i++, vit++)
+    {
+        *vit = (*vit) / normalizationRatio;
+    }
+}
+
+double
+WifiSpectrumValueHelper::DbmToW(double dBm)
+{
+    return std::pow(10.0, 0.1 * (dBm - 30.0));
+}
+
+double
+WifiSpectrumValueHelper::GetBandPowerW(Ptr<SpectrumValue> psd, const WifiSpectrumBandIndices& band)
+{
+    auto valueIt = psd->ConstValuesBegin() + band.first;
+    auto end = psd->ConstValuesBegin() + band.second;
+    auto bandIt = psd->ConstBandsBegin() + band.first; // all bands have same width
+    const auto bandWidth = (bandIt->fh - bandIt->fl);
+    NS_ASSERT_MSG(bandWidth >= 0.0,
+                  "Invalid width for subband [" << bandIt->fl << ";" << bandIt->fh << "]");
+    uint32_t index{0};
+    auto powerWattPerHertz{0.0};
+    while (valueIt <= end)
+    {
+        NS_ASSERT_MSG(*valueIt >= 0.0,
+                      "Invalid power value " << *valueIt << " in subband " << index);
+        powerWattPerHertz += *valueIt;
+        ++valueIt;
+        ++index;
+    }
+    const auto power = powerWattPerHertz * bandWidth;
+    NS_ASSERT_MSG(power >= 0.0,
+                  "Invalid calculated power " << power << " for band [" << band.first << ";"
+                                              << band.second << "]");
+    return power;
+}
+
+bool
+operator<(const FrequencyRange& left, const FrequencyRange& right)
+{
+    return left.minFrequency < right.minFrequency;
+}
+
+bool
+operator==(const FrequencyRange& left, const FrequencyRange& right)
+{
+    return (left.minFrequency == right.minFrequency) && (left.maxFrequency == right.maxFrequency);
+}
+
+bool
+operator!=(const FrequencyRange& left, const FrequencyRange& right)
+{
+    return !(left == right);
+}
+
+std::ostream&
+operator<<(std::ostream& os, const FrequencyRange& freqRange)
+{
+    os << "[" << freqRange.minFrequency << " MHz - " << freqRange.maxFrequency << " MHz]";
+    return os;
+}
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-spectrum-value-helper.h ns-3.42/src/wifi/model/wifi-spectrum-value-helper.h
--- ns-3.41/src/wifi/model/wifi-spectrum-value-helper.h	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/wifi-spectrum-value-helper.h	2024-05-29 15:29:47.216073800 -0700
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2009 CTTC
+ * Copyright (c) 2017 Orange Labs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Nicola Baldo <nbaldo@cttc.es>
+ *          Rediet <getachew.redieteab@orange.com>
+ */
+
+#ifndef WIFI_SPECTRUM_VALUE_HELPER_H
+#define WIFI_SPECTRUM_VALUE_HELPER_H
+
+#include <ns3/spectrum-value.h>
+
+namespace ns3
+{
+
+/**
+ * typedef for a pair of start and stop sub-band indices
+ */
+using WifiSpectrumBandIndices = std::pair<uint32_t, uint32_t>;
+
+/**
+ * \ingroup spectrum
+ *
+ *  This class defines all functions to create a spectrum model for
+ *  Wi-Fi based on a a spectral model aligned with an OFDM subcarrier
+ *  spacing of 312.5 KHz (model also reused for DSSS modulations)
+ */
+class WifiSpectrumValueHelper
+{
+  public:
+    /**
+     * Destructor
+     */
+    virtual ~WifiSpectrumValueHelper() = default;
+
+    /**
+     * Return a SpectrumModel instance corresponding to the center frequency
+     * and channel width.  The spectrum model spans the channel width
+     * +/- the guard bands (i.e. the model will span (channelWidth +
+     * 2 * guardBandwidth) MHz of bandwidth).
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param carrierSpacing carrier spacing (Hz)
+     * \param guardBandwidth width of the guard band (MHz)
+     *
+     * \return the static SpectrumModel instance corresponding to the
+     * given carrier frequency and channel width configuration.
+     */
+    static Ptr<SpectrumModel> GetSpectrumModel(uint32_t centerFrequency,
+                                               uint16_t channelWidth,
+                                               uint32_t carrierSpacing,
+                                               uint16_t guardBandwidth);
+
+    /**
+     * Create a transmit power spectral density corresponding to DSSS
+     *
+     * The center frequency typically corresponds to 802.11b channel
+     * center frequencies but is not restricted to those frequencies.
+     *
+     * \note There is no channel width parameter; this method assumes 22 MHz
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param txPowerW  transmit power (W) to allocate
+     * \param guardBandwidth width of the guard band (MHz)
+     * \returns a pointer to a newly allocated SpectrumValue representing the DSSS Transmit Power
+     * Spectral Density in W/Hz
+     */
+    static Ptr<SpectrumValue> CreateDsssTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                               double txPowerW,
+                                                               uint16_t guardBandwidth);
+
+    /**
+     * Create a transmit power spectral density corresponding to OFDM
+     * (802.11a/g).  Channel width may vary between 20, 10, and 5 MHz.
+     * Guard bandwidth also typically varies with channel width.
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param txPowerW  transmit power (W) to allocate
+     * \param guardBandwidth width of the guard band (MHz)
+     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
+     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
+     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
+     * (in dBr)
+     * \return a pointer to a newly allocated SpectrumValue representing the OFDM Transmit Power
+     * Spectral Density in W/Hz for each Band
+     */
+    static Ptr<SpectrumValue> CreateOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                               uint16_t channelWidth,
+                                                               double txPowerW,
+                                                               uint16_t guardBandwidth,
+                                                               double minInnerBandDbr = -20,
+                                                               double minOuterbandDbr = -28,
+                                                               double lowestPointDbr = -40);
+
+    /**
+     * Create a transmit power spectral density corresponding to OFDM duplicated over multiple 20
+     * MHz subchannels. Channel width may vary between 20, 40, 80, and 160 MHz.
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param txPowerW  transmit power (W) to allocate
+     * \param guardBandwidth width of the guard band (MHz)
+     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
+     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
+     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
+     * (in dBr)
+     * \param puncturedSubchannels bitmap indicating whether a 20 MHz subchannel is punctured or not
+     * \return a pointer to a newly allocated SpectrumValue representing the duplicated 20 MHz OFDM
+     * Transmit Power Spectral Density in W/Hz for each Band
+     */
+    static Ptr<SpectrumValue> CreateDuplicated20MhzTxPowerSpectralDensity(
+        uint32_t centerFrequency,
+        uint16_t channelWidth,
+        double txPowerW,
+        uint16_t guardBandwidth,
+        double minInnerBandDbr = -20,
+        double minOuterbandDbr = -28,
+        double lowestPointDbr = -40,
+        const std::vector<bool>& puncturedSubchannels = std::vector<bool>{});
+
+    /**
+     * Create a transmit power spectral density corresponding to OFDM
+     * High Throughput (HT) (802.11n/ac).  Channel width may vary between
+     * 20, 40, 80, and 160 MHz.
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param txPowerW  transmit power (W) to allocate
+     * \param guardBandwidth width of the guard band (MHz)
+     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
+     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
+     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
+     * (in dBr)
+     * \return a pointer to a newly allocated SpectrumValue representing the HT OFDM Transmit Power
+     * Spectral Density in W/Hz for each Band
+     */
+    static Ptr<SpectrumValue> CreateHtOfdmTxPowerSpectralDensity(uint32_t centerFrequency,
+                                                                 uint16_t channelWidth,
+                                                                 double txPowerW,
+                                                                 uint16_t guardBandwidth,
+                                                                 double minInnerBandDbr = -20,
+                                                                 double minOuterbandDbr = -28,
+                                                                 double lowestPointDbr = -40);
+
+    /**
+     * Create a transmit power spectral density corresponding to OFDM
+     * High Efficiency (HE) (802.11ax).  Channel width may vary between
+     * 20, 40, 80, and 160 MHz.
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param txPowerW  transmit power (W) to allocate
+     * \param guardBandwidth width of the guard band (MHz)
+     * \param minInnerBandDbr the minimum relative power in the inner band (in dBr)
+     * \param minOuterbandDbr the minimum relative power in the outer band (in dBr)
+     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
+     * (in dBr)
+     * \param puncturedSubchannels bitmap indicating whether a 20 MHz subchannel is punctured or not
+     * \return a pointer to a newly allocated SpectrumValue representing the HE OFDM Transmit Power
+     * Spectral Density in W/Hz for each Band
+     */
+    static Ptr<SpectrumValue> CreateHeOfdmTxPowerSpectralDensity(
+        uint32_t centerFrequency,
+        uint16_t channelWidth,
+        double txPowerW,
+        uint16_t guardBandwidth,
+        double minInnerBandDbr = -20,
+        double minOuterbandDbr = -28,
+        double lowestPointDbr = -40,
+        const std::vector<bool>& puncturedSubchannels = std::vector<bool>{});
+
+    /**
+     * Create a transmit power spectral density corresponding to the OFDMA part
+     * of HE TB PPDUs for a given RU.
+     * An ideal (i.e. rectangular) spectral mask is considered for the time being.
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param txPowerW  transmit power (W) to allocate
+     * \param guardBandwidth width of the guard band (MHz)
+     * \param ru the RU band used by the STA
+     * \return a pointer to a newly allocated SpectrumValue representing the HE OFDM Transmit Power
+     * Spectral Density on the RU used by the STA in W/Hz for each Band
+     */
+    static Ptr<SpectrumValue> CreateHeMuOfdmTxPowerSpectralDensity(
+        uint32_t centerFrequency,
+        uint16_t channelWidth,
+        double txPowerW,
+        uint16_t guardBandwidth,
+        const WifiSpectrumBandIndices& ru);
+
+    /**
+     * Create a power spectral density corresponding to the noise
+     *
+     * \param centerFrequency center frequency (MHz)
+     * \param channelWidth channel width (MHz)
+     * \param carrierSpacing carrier spacing (Hz)
+     * \param noiseFigure the noise figure in dB w.r.t. a reference temperature of 290K
+     * \param guardBandwidth width of the guard band (MHz)
+     * \return a pointer to a newly allocated SpectrumValue representing the noise Power Spectral
+     * Density in W/Hz for each Band
+     */
+    static Ptr<SpectrumValue> CreateNoisePowerSpectralDensity(uint32_t centerFrequency,
+                                                              uint16_t channelWidth,
+                                                              uint32_t carrierSpacing,
+                                                              double noiseFigure,
+                                                              uint16_t guardBandwidth);
+
+    /**
+     * Create a thermal noise power spectral density
+     *
+     * \param noiseFigure the noise figure
+     * \param spectrumModel the spectrum model
+     * \return a pointer to a newly allocated SpectrumValue representing the noise Power Spectral
+     * Density in W/Hz corresponding to thermal noise, for each Band
+     */
+    static Ptr<SpectrumValue> CreateNoisePowerSpectralDensity(double noiseFigure,
+                                                              Ptr<SpectrumModel> spectrumModel);
+
+    /**
+     * Create a transmit power spectral density corresponding to OFDM
+     * transmit spectrum mask requirements for 11a/11g/11n/11ac/11ax
+     * Channel width may vary between 5, 10, 20, 40, 80, and 160 MHz.
+     * The default (standard) values are illustrated below.
+     *
+     *   [ guard band  ][    channel width     ][  guard band ]
+     *                   __________   __________                  _ 0 dBr
+     *                  /          | |          \
+     *                 /           |_|           \                _ -20 dBr
+     *             . '                             ' .
+     *         . '                                     ' .        _ -28 dBr
+     *       .'                                           '.
+     *     .'                                               '.
+     *   .'                                                   '.  _ lowest point
+     *
+     *   |-----|                                         |-----|  outerBand left/right
+     *         |------|                           |-- ---|        middle band left/right
+     *                |-|                       |-|               inner band left/right
+     *                  |-----------------------|                 allocated sub-bands
+     *   |-----------------------------------------------------|  mask band
+     *
+     * Please take note that, since guard tones are within the allocated band
+     * while not being ideally allocated any power, the inner band had to be
+     * shifted inwards and a flat junction band (at -20 dBr) had to be added
+     * between the inner and the middle bands.
+     *
+     * \param c spectrumValue to allocate according to transmit power spectral density mask (in W/Hz
+     * for each band)
+     * \param allocatedSubBands vector of start and stop subcarrier indexes of the allocated sub
+     * bands
+     * \param maskBand start and stop subcarrier indexes of transmit mask (in case signal doesn't
+     * cover whole SpectrumModel)
+     * \param txPowerPerBandW power allocated to each subcarrier in the allocated sub bands
+     * \param nGuardBands size (in number of subcarriers) of the guard band (left and right)
+     * \param innerSlopeWidth size (in number of subcarriers) of the inner band (i.e. slope going
+     * from 0 dBr to -20 dBr in the figure above)
+     * \param minInnerBandDbr the minimum relative power in the inner band (i.e., -20 dBr in the
+     * figure above)
+     * \param minOuterbandDbr the minimum relative power in the outer band (i.e., -28 dBr in the
+     * figure above)
+     * \param lowestPointDbr maximum relative power of the outermost subcarriers of the guard band
+     * (in dBr)
+     * \param puncturedSubBands vector of start and stop subcarrier indexes of the punctured sub
+     * bands
+     * \param puncturedSlopeWidth size (in number of subcarriers) of the punctured band slope
+     */
+    static void CreateSpectrumMaskForOfdm(
+        Ptr<SpectrumValue> c,
+        const std::vector<WifiSpectrumBandIndices>& allocatedSubBands,
+        const WifiSpectrumBandIndices& maskBand,
+        double txPowerPerBandW,
+        uint32_t nGuardBands,
+        uint32_t innerSlopeWidth,
+        double minInnerBandDbr,
+        double minOuterbandDbr,
+        double lowestPointDbr,
+        const std::vector<WifiSpectrumBandIndices>& puncturedSubBands =
+            std::vector<WifiSpectrumBandIndices>{},
+        uint32_t puncturedSlopeWidth = 0);
+
+    /**
+     * Normalize the transmit spectrum mask generated by CreateSpectrumMaskForOfdm
+     * so that the total transmitted power corresponds to the input value.
+     *
+     * \param c spectrumValue to normalize (in W/Hz for each band)
+     * \param txPowerW total transmit power (W) to allocate
+     */
+    static void NormalizeSpectrumMask(Ptr<SpectrumValue> c, double txPowerW);
+
+    /**
+     * Convert from dBm to Watts.
+     * Taken from wifi-utils since the original method couldn't be called from here
+     * due to resulting circular dependencies of spectrum and wifi modules.
+     *
+     * \param dbm the power in dBm
+     *
+     * \return the equivalent Watts for the given dBm
+     */
+    static double DbmToW(double dbm);
+
+    /**
+     * Calculate the power of the specified band composed of uniformly-sized sub-bands.
+     *
+     * \param psd received Power Spectral Density in W/Hz
+     * \param band a pair of start and stop indexes that defines the band
+     *
+     * \return band power in W
+     */
+    static double GetBandPowerW(Ptr<SpectrumValue> psd, const WifiSpectrumBandIndices& band);
+};
+
+/**
+ * \ingroup spectrum
+ * Struct defining a frequency range between minFrequency (MHz) and maxFrequency (MHz).
+ */
+struct FrequencyRange
+{
+    uint16_t minFrequency{0}; ///< the minimum frequency in MHz
+    uint16_t maxFrequency{0}; ///< the maximum frequency in MHz
+};
+
+/**
+ * Compare two FrequencyRange values
+ *
+ * \param lhs the FrequencyRange value on the left of operator
+ * \param rhs the FrequencyRange value on the right of operator
+ *
+ * \return true if minFrequency of left is less than minFrequency of right, false otherwise
+ */
+bool operator<(const FrequencyRange& lhs, const FrequencyRange& rhs);
+
+/**
+ * Compare two FrequencyRange values
+ *
+ * \param lhs the FrequencyRange value on the left of operator
+ * \param rhs the FrequencyRange value on the right of operator
+ *
+ * \return true if both minFrequency and maxFrequency of left are equal to minFrequency and
+ * maxFrequency of right respectively, false otherwise
+ */
+bool operator==(const FrequencyRange& lhs, const FrequencyRange& rhs);
+
+/**
+ * Compare two FrequencyRange values
+ *
+ * \param lhs the FrequencyRange value on the left of operator
+ * \param rhs the FrequencyRange value on the right of operator
+ *
+ * \return true if either minFrequency or maxFrequency of left different from minFrequency or
+ * maxFrequency of right respectively, false otherwise
+ */
+bool operator!=(const FrequencyRange& lhs, const FrequencyRange& rhs);
+
+/**
+ * Serialize FrequencyRange values to ostream (human-readable).
+ *
+ * \param os the output stream
+ * \param freqRange the FrequencyRange
+ *
+ * \return std::ostream
+ */
+std::ostream& operator<<(std::ostream& os, const FrequencyRange& freqRange);
+
+/// Identifier for the frequency range covering the whole wifi spectrum
+constexpr FrequencyRange WHOLE_WIFI_SPECTRUM = {2401, 7125};
+
+/// Identifier for the frequency range covering the wifi spectrum in the 2.4 GHz band
+constexpr FrequencyRange WIFI_SPECTRUM_2_4_GHZ = {2401, 2483};
+
+/// Identifier for the frequency range covering the wifi spectrum in the 5 GHz band
+constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ = {5170, 5915};
+
+/// Identifier for the frequency range covering the wifi spectrum in the 6 GHz band
+constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ = {5945, 7125};
+
+} // namespace ns3
+
+#endif /*  WIFI_SPECTRUM_VALUE_HELPER_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-standards.cc ns-3.42/src/wifi/model/wifi-standards.cc
--- ns-3.41/src/wifi/model/wifi-standards.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/model/wifi-standards.cc	2024-05-29 15:29:47.216073800 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "wifi-standards.h"
+
+namespace ns3
+{
+
+const std::map<WifiStandard, std::list<WifiPhyBand>> wifiStandards = {
+    {WIFI_STANDARD_80211a, {WIFI_PHY_BAND_5GHZ}},
+    {WIFI_STANDARD_80211b, {WIFI_PHY_BAND_2_4GHZ}},
+    {WIFI_STANDARD_80211g, {WIFI_PHY_BAND_2_4GHZ}},
+    {WIFI_STANDARD_80211p, {WIFI_PHY_BAND_5GHZ}},
+    {WIFI_STANDARD_80211n, {WIFI_PHY_BAND_2_4GHZ, WIFI_PHY_BAND_5GHZ}},
+    {WIFI_STANDARD_80211ac, {WIFI_PHY_BAND_5GHZ}},
+    {WIFI_STANDARD_80211ad, {WIFI_PHY_BAND_60GHZ}},
+    {WIFI_STANDARD_80211ax, {WIFI_PHY_BAND_2_4GHZ, WIFI_PHY_BAND_5GHZ, WIFI_PHY_BAND_6GHZ}},
+    {WIFI_STANDARD_80211be, {WIFI_PHY_BAND_2_4GHZ, WIFI_PHY_BAND_5GHZ, WIFI_PHY_BAND_6GHZ}},
+};
+
+} // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-standards.h ns-3.42/src/wifi/model/wifi-standards.h
--- ns-3.41/src/wifi/model/wifi-standards.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-standards.h	2024-05-29 15:29:47.216073800 -0700
@@ -45,7 +45,8 @@
     WIFI_STANDARD_80211ac,
     WIFI_STANDARD_80211ad,
     WIFI_STANDARD_80211ax,
-    WIFI_STANDARD_80211be
+    WIFI_STANDARD_80211be,
+    WIFI_STANDARD_COUNT
 };
 
 /**
@@ -86,17 +87,7 @@
 /**
  * \brief map a given standard configured by the user to the allowed PHY bands
  */
-const std::map<WifiStandard, std::list<WifiPhyBand>> wifiStandards = {
-    {WIFI_STANDARD_80211a, {WIFI_PHY_BAND_5GHZ}},
-    {WIFI_STANDARD_80211b, {WIFI_PHY_BAND_2_4GHZ}},
-    {WIFI_STANDARD_80211g, {WIFI_PHY_BAND_2_4GHZ}},
-    {WIFI_STANDARD_80211p, {WIFI_PHY_BAND_5GHZ}},
-    {WIFI_STANDARD_80211n, {WIFI_PHY_BAND_2_4GHZ, WIFI_PHY_BAND_5GHZ}},
-    {WIFI_STANDARD_80211ac, {WIFI_PHY_BAND_5GHZ}},
-    {WIFI_STANDARD_80211ad, {WIFI_PHY_BAND_60GHZ}},
-    {WIFI_STANDARD_80211ax, {WIFI_PHY_BAND_2_4GHZ, WIFI_PHY_BAND_5GHZ, WIFI_PHY_BAND_6GHZ}},
-    {WIFI_STANDARD_80211be, {WIFI_PHY_BAND_2_4GHZ, WIFI_PHY_BAND_5GHZ, WIFI_PHY_BAND_6GHZ}},
-};
+extern const std::map<WifiStandard, std::list<WifiPhyBand>> wifiStandards;
 
 /**
  * \ingroup wifi
@@ -181,6 +172,39 @@
     }
 }
 
+/**
+ * Get the TypeId name for the FrameExchangeManager corresponding to the given standard.
+ *
+ * \param standard the given standard
+ * \param qosSupported whether QoS is supported (ignored if standard is at least HT)
+ * \return the TypeId name for the FrameExchangeManager corresponding to the given standard
+ */
+inline std::string
+GetFrameExchangeManagerTypeIdName(WifiStandard standard, bool qosSupported)
+{
+    if (standard >= WIFI_STANDARD_80211be)
+    {
+        return "ns3::EhtFrameExchangeManager";
+    }
+    if (standard >= WIFI_STANDARD_80211ax)
+    {
+        return "ns3::HeFrameExchangeManager";
+    }
+    if (standard >= WIFI_STANDARD_80211ac)
+    {
+        return "ns3::VhtFrameExchangeManager";
+    }
+    if (standard >= WIFI_STANDARD_80211n)
+    {
+        return "ns3::HtFrameExchangeManager";
+    }
+    if (qosSupported)
+    {
+        return "ns3::QosFrameExchangeManager";
+    }
+    return "ns3::FrameExchangeManager";
+}
+
 } // namespace ns3
 
 #endif /* WIFI_STANDARD_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-tx-parameters.cc ns-3.42/src/wifi/model/wifi-tx-parameters.cc
--- ns-3.41/src/wifi/model/wifi-tx-parameters.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-tx-parameters.cc	2024-05-29 15:29:47.216073800 -0700
@@ -75,7 +75,7 @@
     m_txVector = WifiTxVector();
     m_protection.reset(nullptr);
     m_acknowledgment.reset(nullptr);
-    m_txDuration = Time::Min();
+    m_txDuration.reset();
 }
 
 const WifiTxParameters::PsduInfo*
@@ -115,7 +115,13 @@
         }
 
         // Insert the info about the given frame
-        m_info.emplace(hdr.GetAddr1(), PsduInfo{hdr, mpdu->GetPacketSize(), 0, seqNumbers});
+        const auto [it, inserted] =
+            m_info.emplace(hdr.GetAddr1(), PsduInfo{hdr, mpdu->GetPacketSize(), 0, seqNumbers});
+        NS_ASSERT(inserted);
+
+        // store information to undo the addition of this MPDU
+        m_lastInfoIt = it;
+        m_undoInfo = PsduInfo{WifiMacHeader{}, 0, 0, {}};
         return;
     }
 
@@ -123,6 +129,16 @@
     NS_ASSERT_MSG((hdr.IsQosData() && !hdr.HasData()) || infoIt->second.amsduSize > 0,
                   "An MPDU can only be aggregated to an existing (A-)MPDU");
 
+    // store information to undo the addition of this MPDU
+    m_lastInfoIt = infoIt;
+    m_undoInfo =
+        PsduInfo{infoIt->second.header, infoIt->second.amsduSize, infoIt->second.ampduSize, {}};
+    if (hdr.IsQosData())
+    {
+        m_undoInfo.seqNumbers = {
+            {hdr.GetQosTid(), {hdr.GetSequenceNumber()}}}; // seq number to remove
+    }
+
     // The (A-)MSDU being built is included in an A-MPDU subframe
     infoIt->second.ampduSize = MpduAggregator::GetSizeIfAggregated(
         infoIt->second.header.GetSize() + infoIt->second.amsduSize + WIFI_MAC_FCS_LENGTH,
@@ -132,17 +148,59 @@
 
     if (hdr.IsQosData())
     {
-        auto ret = infoIt->second.seqNumbers.emplace(hdr.GetQosTid(),
-                                                     std::set<uint16_t>{hdr.GetSequenceNumber()});
+        const auto [it, inserted] =
+            infoIt->second.seqNumbers.emplace(hdr.GetQosTid(),
+                                              std::set<uint16_t>{hdr.GetSequenceNumber()});
 
-        if (!ret.second)
+        if (!inserted)
         {
             // insertion did not happen because an entry with the same TID already exists
-            ret.first->second.insert(hdr.GetSequenceNumber());
+            it->second.insert(hdr.GetSequenceNumber());
         }
     }
 }
 
+void
+WifiTxParameters::UndoAddMpdu()
+{
+    NS_LOG_FUNCTION(this);
+    NS_ASSERT(m_lastInfoIt.has_value());
+
+    if (m_undoInfo.amsduSize == 0 && m_undoInfo.ampduSize == 0)
+    {
+        // the last MPDU was the first one being added for its receiver
+        m_info.erase(*m_lastInfoIt);
+        m_lastInfoIt.reset();
+        return;
+    }
+
+    auto& lastInfo = (*m_lastInfoIt)->second;
+    lastInfo.header = m_undoInfo.header;
+    lastInfo.amsduSize = m_undoInfo.amsduSize;
+    lastInfo.ampduSize = m_undoInfo.ampduSize;
+    // if the MPDU to remove is not a QoS data frame or it is the first QoS data frame added for
+    // a given receiver, no sequence number information is stored
+    if (!m_undoInfo.seqNumbers.empty())
+    {
+        NS_ASSERT(m_undoInfo.seqNumbers.size() == 1);
+        const auto tid = m_undoInfo.seqNumbers.cbegin()->first;
+        auto& seqNoSet = m_undoInfo.seqNumbers.cbegin()->second;
+        NS_ASSERT(seqNoSet.size() == 1);
+        NS_ASSERT(lastInfo.seqNumbers.contains(tid));
+        lastInfo.seqNumbers.at(tid).erase(*seqNoSet.cbegin());
+    }
+    m_lastInfoIt.reset();
+}
+
+bool
+WifiTxParameters::LastAddedIsFirstMpdu(Mac48Address receiver) const
+{
+    auto infoIt = m_info.find(receiver);
+    NS_ASSERT_MSG(infoIt != m_info.cend(), "No frame added for receiver " << receiver);
+    NS_ASSERT_MSG(m_lastInfoIt == infoIt, "Last MPDU not addressed to " << receiver);
+    return (m_undoInfo.amsduSize == 0 && m_undoInfo.ampduSize == 0);
+}
+
 uint32_t
 WifiTxParameters::GetSizeIfAddMpdu(Ptr<const WifiMpdu> mpdu) const
 {
@@ -178,11 +236,16 @@
     NS_ASSERT_MSG(infoIt != m_info.end(),
                   "There must be already an MPDU addressed to the same receiver");
 
-    infoIt->second.amsduSize = GetSizeIfAggregateMsdu(msdu).first;
+    // store information to undo the addition of this MSDU
+    m_lastInfoIt = infoIt;
+    m_undoInfo =
+        PsduInfo{infoIt->second.header, infoIt->second.amsduSize, infoIt->second.ampduSize, {}};
+
+    infoIt->second.amsduSize = GetSizeIfAggregateMsdu(msdu);
     infoIt->second.header.SetQosAmsdu();
 }
 
-std::pair<uint32_t, uint32_t>
+uint32_t
 WifiTxParameters::GetSizeIfAggregateMsdu(Ptr<const WifiMpdu> msdu) const
 {
     NS_LOG_FUNCTION(this << *msdu);
@@ -200,8 +263,7 @@
                   "The MPDU being built for this receiver must be a QoS data frame");
     NS_ASSERT_MSG(infoIt->second.header.GetQosTid() == msdu->GetHeader().GetQosTid(),
                   "The MPDU being built must belong to the same TID as the MSDU to aggregate");
-    NS_ASSERT_MSG(infoIt->second.seqNumbers.find(msdu->GetHeader().GetQosTid()) !=
-                      infoIt->second.seqNumbers.end(),
+    NS_ASSERT_MSG(infoIt->second.seqNumbers.contains(msdu->GetHeader().GetQosTid()),
                   "At least one MPDU with the same TID must have been added previously");
 
     // all checks passed
@@ -213,17 +275,7 @@
         currAmsduSize = MsduAggregator::GetSizeIfAggregated(currAmsduSize, 0);
     }
 
-    uint32_t newAmsduSize =
-        MsduAggregator::GetSizeIfAggregated(msdu->GetPacket()->GetSize(), currAmsduSize);
-    uint32_t newMpduSize = infoIt->second.header.GetSize() + newAmsduSize + WIFI_MAC_FCS_LENGTH;
-
-    if (infoIt->second.ampduSize > 0 || m_txVector.GetModulationClass() >= WIFI_MOD_CLASS_VHT)
-    {
-        return {newAmsduSize,
-                MpduAggregator::GetSizeIfAggregated(newMpduSize, infoIt->second.ampduSize)};
-    }
-
-    return {newAmsduSize, newMpduSize};
+    return MsduAggregator::GetSizeIfAggregated(msdu->GetPacket()->GetSize(), currAmsduSize);
 }
 
 uint32_t
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-tx-parameters.h ns-3.42/src/wifi/model/wifi-tx-parameters.h
--- ns-3.41/src/wifi/model/wifi-tx-parameters.h	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-tx-parameters.h	2024-05-29 15:29:47.216073800 -0700
@@ -27,6 +27,7 @@
 
 #include <map>
 #include <memory>
+#include <optional>
 #include <set>
 
 namespace ns3
@@ -61,10 +62,24 @@
      */
     WifiTxParameters& operator=(const WifiTxParameters& txParams);
 
+    /**
+     * Move constructor. Must define it manually because copy constructor is explicit.
+     * \param txParams the WifiTxParameters to copy
+     */
+    WifiTxParameters(WifiTxParameters&& txParams) = default;
+
+    /**
+     * Move assignment operator. Must define it manually because copy assignment
+     * operator is explicit.
+     * \param txParams the TX parameters to assign to this object
+     * \return the reference to this object
+     */
+    WifiTxParameters& operator=(WifiTxParameters&& txParams) = default;
+
     WifiTxVector m_txVector;                              //!< TXVECTOR of the frame being prepared
     std::unique_ptr<WifiProtection> m_protection;         //!< protection method
     std::unique_ptr<WifiAcknowledgment> m_acknowledgment; //!< acknowledgment method
-    Time m_txDuration{Time::Min()};                       //!< TX duration of the frame
+    std::optional<Time> m_txDuration;                     //!< TX duration of the frame
 
     /**
      * Reset the TX parameters.
@@ -74,12 +89,27 @@
     /**
      * Record that an MPDU is being added to the current frame. If an MPDU addressed
      * to the same receiver already exists in the frame, A-MPDU aggregation is considered.
+     * Store information needed to "undo" the addition of the MPDU by calling UndoAddMpdu().
      *
      * \param mpdu the MPDU being added
      */
     void AddMpdu(Ptr<const WifiMpdu> mpdu);
 
     /**
+     * Undo the addition of the last MPDU added by calling AddMpdu().
+     */
+    void UndoAddMpdu();
+
+    /**
+     * Check if the last added MPDU is the first MPDU for the given receiver.
+     * Call this method only after adding an MPDU for the given receiver.
+     *
+     * \param receiver the MAC address of the given receiver
+     * \return whether the last added MPDU is the first MPDU for the given receiver
+     */
+    bool LastAddedIsFirstMpdu(Mac48Address receiver) const;
+
+    /**
      * Record that an MSDU is being aggregated to the last MPDU added to the frame
      * that hase the same receiver.
      *
@@ -99,10 +129,9 @@
      * Get the size in bytes of the frame in case the given MSDU is aggregated.
      *
      * \param msdu the given MSDU
-     * \return a pair (size in bytes of the current A-MSDU, size in bytes of the frame)
-               in case the given MSDU is aggregated
+     * \return size in bytes of the frame in case the given MSDU is aggregated
      */
-    std::pair<uint32_t, uint32_t> GetSizeIfAggregateMsdu(Ptr<const WifiMpdu> msdu) const;
+    uint32_t GetSizeIfAggregateMsdu(Ptr<const WifiMpdu> msdu) const;
 
     /**
      * Get the size in bytes of the (A-)MPDU addressed to the given receiver.
@@ -150,8 +179,12 @@
     void Print(std::ostream& os) const;
 
   private:
-    PsduInfoMap m_info; //!< information about the frame being prepared. Handles
-                        //!< multi-TID A-MPDUs, MU PPDUs, etc.
+    PsduInfoMap m_info;    //!< information about the frame being prepared. Handles
+                           //!< multi-TID A-MPDUs, MU PPDUs, etc.
+    PsduInfo m_undoInfo{}; //!< information needed to undo the addition of an MPDU
+    std::optional<PsduInfoMap::iterator>
+        m_lastInfoIt; //!< iterator pointing to the entry in the m_info map
+                      //!< that was created/modified by the last added MPDU
 };
 
 /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-tx-timer.cc ns-3.42/src/wifi/model/wifi-tx-timer.cc
--- ns-3.41/src/wifi/model/wifi-tx-timer.cc	2024-02-09 14:44:08.605795100 -0800
+++ ns-3.42/src/wifi/model/wifi-tx-timer.cc	2024-05-29 15:29:47.216073800 -0700
@@ -49,7 +49,7 @@
 {
     NS_LOG_FUNCTION(this << delay);
 
-    if (m_timeoutEvent.IsRunning())
+    if (m_timeoutEvent.IsPending())
     {
         NS_LOG_DEBUG("Rescheduling " << GetReasonString(m_reason) << " timeout in "
                                      << delay.As(Time::US));
@@ -120,7 +120,7 @@
 bool
 WifiTxTimer::IsRunning() const
 {
-    return m_timeoutEvent.IsRunning();
+    return m_timeoutEvent.IsPending();
 }
 
 void
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-tx-vector.cc ns-3.42/src/wifi/model/wifi-tx-vector.cc
--- ns-3.41/src/wifi/model/wifi-tx-vector.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/model/wifi-tx-vector.cc	2024-05-29 15:29:47.216073800 -0700
@@ -205,7 +205,7 @@
     if (IsMu())
     {
         NS_ABORT_MSG_IF(staId > 2048, "STA-ID should be correctly set for MU (" << staId << ")");
-        NS_ASSERT(m_muUserInfos.find(staId) != m_muUserInfos.end());
+        NS_ASSERT(m_muUserInfos.contains(staId));
         return m_muUserInfos.at(staId).nss;
     }
     return m_nss;
@@ -605,7 +605,7 @@
 bool
 WifiTxVector::IsAllocated(uint16_t staId) const
 {
-    return m_muUserInfos.count(staId) > 0;
+    return m_muUserInfos.contains(staId);
 }
 
 HeRu::RuSpec
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-utils.cc ns-3.42/src/wifi/model/wifi-utils.cc
--- ns-3.41/src/wifi/model/wifi-utils.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/model/wifi-utils.cc	2024-05-29 15:29:47.216073800 -0700
@@ -30,6 +30,8 @@
 namespace ns3
 {
 
+const Time WIFI_TU = MicroSeconds(WIFI_TU_US);
+
 double
 DbToRatio(double dB)
 {
@@ -57,9 +59,9 @@
 uint32_t
 GetAckSize()
 {
-    WifiMacHeader ack;
-    ack.SetType(WIFI_MAC_CTL_ACK);
-    return ack.GetSize() + 4;
+    static const uint32_t size = WifiMacHeader(WIFI_MAC_CTL_ACK).GetSize() + 4;
+
+    return size;
 }
 
 uint32_t
@@ -102,17 +104,17 @@
 uint32_t
 GetRtsSize()
 {
-    WifiMacHeader rts;
-    rts.SetType(WIFI_MAC_CTL_RTS);
-    return rts.GetSize() + 4;
+    static const uint32_t size = WifiMacHeader(WIFI_MAC_CTL_RTS).GetSize() + 4;
+
+    return size;
 }
 
 uint32_t
 GetCtsSize()
 {
-    WifiMacHeader cts;
-    cts.SetType(WIFI_MAC_CTL_CTS);
-    return cts.GetSize() + 4;
+    static const uint32_t size = WifiMacHeader(WIFI_MAC_CTL_CTS).GetSize() + 4;
+
+    return size;
 }
 
 bool
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/wifi-utils.h ns-3.42/src/wifi/model/wifi-utils.h
--- ns-3.41/src/wifi/model/wifi-utils.h	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/model/wifi-utils.h	2024-05-29 15:29:47.216073800 -0700
@@ -23,6 +23,7 @@
 #include "block-ack-type.h"
 
 #include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
 #include "ns3/ptr.h"
 
 #include <list>
@@ -194,6 +195,13 @@
 /// Invalid link identifier
 static constexpr uint8_t WIFI_LINKID_UNDEFINED = 0xff;
 
+/// Wi-Fi Time Unit value in microseconds (see IEEE 802.11-2020 sec. 3.1)
+/// Used to initialize WIFI_TU
+constexpr int WIFI_TU_US = 1024;
+
+/// Wi-Fi Time Unit (see IEEE 802.11-2020 sec. 3.1)
+extern const Time WIFI_TU;
+
 } // namespace ns3
 
 #endif /* WIFI_UTILS_H */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/yans-wifi-channel.cc ns-3.42/src/wifi/model/yans-wifi-channel.cc
--- ns-3.41/src/wifi/model/yans-wifi-channel.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/model/yans-wifi-channel.cc	2024-05-29 15:29:47.216073800 -0700
@@ -134,18 +134,19 @@
 YansWifiChannel::Receive(Ptr<YansWifiPhy> phy, Ptr<const WifiPpdu> ppdu, double rxPowerDbm)
 {
     NS_LOG_FUNCTION(phy << ppdu << rxPowerDbm);
+    const auto totalRxPowerDbm = rxPowerDbm + phy->GetRxGain();
+    phy->TraceSignalArrival(ppdu, totalRxPowerDbm, ppdu->GetTxDuration());
     // Do no further processing if signal is too weak
     // Current implementation assumes constant RX power over the PPDU duration
     // Compare received TX power per MHz to normalized RX sensitivity
     uint16_t txWidth = ppdu->GetTxChannelWidth();
-    if ((rxPowerDbm + phy->GetRxGain()) < phy->GetRxSensitivity() + RatioToDb(txWidth / 20.0))
+    if (totalRxPowerDbm < phy->GetRxSensitivity() + RatioToDb(txWidth / 20.0))
     {
         NS_LOG_INFO("Received signal too weak to process: " << rxPowerDbm << " dBm");
         return;
     }
     RxPowerWattPerChannelBand rxPowerW;
-    rxPowerW.insert(
-        {{{0, 0}, {0, 0}}, (DbmToW(rxPowerDbm + phy->GetRxGain()))}); // dummy band for YANS
+    rxPowerW.insert({{{0, 0}, {0, 0}}, DbmToW(totalRxPowerDbm)}); // dummy band for YANS
     phy->StartReceivePreamble(ppdu, rxPowerW, ppdu->GetTxDuration());
 }
 
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/yans-wifi-phy.cc ns-3.42/src/wifi/model/yans-wifi-phy.cc
--- ns-3.41/src/wifi/model/yans-wifi-phy.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/model/yans-wifi-phy.cc	2024-05-29 15:29:47.216073800 -0700
@@ -36,10 +36,15 @@
 TypeId
 YansWifiPhy::GetTypeId()
 {
-    static TypeId tid = TypeId("ns3::YansWifiPhy")
-                            .SetParent<WifiPhy>()
-                            .SetGroupName("Wifi")
-                            .AddConstructor<YansWifiPhy>();
+    static TypeId tid =
+        TypeId("ns3::YansWifiPhy")
+            .SetParent<WifiPhy>()
+            .SetGroupName("Wifi")
+            .AddConstructor<YansWifiPhy>()
+            .AddTraceSource("SignalArrival",
+                            "Trace start of all signal arrivals, including weak signals",
+                            MakeTraceSourceAccessor(&YansWifiPhy::m_signalArrivalCb),
+                            "ns3::YansWifiPhy::SignalArrivalCallback");
     return tid;
 }
 
@@ -89,9 +94,17 @@
     NS_LOG_FUNCTION(this << ppdu);
     NS_LOG_DEBUG("Start transmission: signal power before antenna gain="
                  << GetPowerDbm(ppdu->GetTxVector().GetTxPowerLevel()) << "dBm");
+    m_signalTransmissionCb(ppdu, ppdu->GetTxVector());
     m_channel->Send(this, ppdu, GetTxPowerForTransmission(ppdu) + GetTxGain());
 }
 
+void
+YansWifiPhy::TraceSignalArrival(Ptr<const WifiPpdu> ppdu, double rxPowerDbm, Time duration)
+{
+    NS_LOG_FUNCTION(this << ppdu);
+    m_signalArrivalCb(ppdu, rxPowerDbm, ppdu->GetTxDuration());
+}
+
 uint16_t
 YansWifiPhy::GetGuardBandwidth(uint16_t currentChannelWidth) const
 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/model/yans-wifi-phy.h ns-3.42/src/wifi/model/yans-wifi-phy.h
--- ns-3.41/src/wifi/model/yans-wifi-phy.h	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/model/yans-wifi-phy.h	2024-05-29 15:29:47.216073800 -0700
@@ -73,11 +73,35 @@
      */
     void SetChannel(const Ptr<YansWifiChannel> channel);
 
+    /**
+     * Logs the arrival of a PPDU, including its power and duration.
+     * This will also trace PPDUs below WifiPhy::RxSensitivity
+     *
+     * \param [in] ppdu The PPDU being traced upon its arrival.
+     * \param [in] rxPowerDbm The received power of the PPDU in dBm.
+     * \param [in] duration The duration of the PPDU signal.
+     */
+    void TraceSignalArrival(Ptr<const WifiPpdu> ppdu, double rxPowerDbm, Time duration);
+
+    /**
+     * Callback invoked when the PHY model starts to process a signal
+     *
+     * \param ppdu The PPDU being processed
+     * \param rxPowerDbm received signal power (dBm)
+     * \param duration Signal duration
+     */
+    typedef void (*SignalArrivalCallback)(Ptr<const WifiPpdu> ppdu,
+                                          double rxPowerDbm,
+                                          Time duration);
+
   protected:
     void DoDispose() override;
 
   private:
     Ptr<YansWifiChannel> m_channel; //!< YansWifiChannel that this YansWifiPhy is connected to
+
+    TracedCallback<Ptr<const WifiPpdu>, double, Time>
+        m_signalArrivalCb; //!< Signal Arrival callback
 };
 
 } // namespace ns3
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/80211b.c ns-3.42/src/wifi/test/80211b.c
--- ns-3.41/src/wifi/test/80211b.c	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/80211b.c	2024-05-29 15:29:47.216073800 -0700
@@ -17,9 +17,13 @@
  * Author: Gary Pei <guangyu.pei@boeing.com>
  */
 
-/*
+/**
+ * \file
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
  * This program is used to generate plots found in the paper
- * G. Pei and Tom Henderson, "Validation of ns-3 802.11b PHY model",
+ * Guangyu Pei and Tom Henderson, "Validation of ns-3 802.11b PHY model",
  * available online at http://www.nsnam.org/~pei/80211b.pdf
  *
  * It can be compiled as a C program and relies on a library installation of
@@ -33,6 +37,13 @@
  *   gnuplot 80211b.plt
  */
 
+/**
+ * \ingroup wifi
+ * \defgroup wifi-test wifi module tests
+ */
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
 #include <gsl/gsl_cdf.h>
 #include <gsl/gsl_integration.h>
 #include <gsl/gsl_math.h>
@@ -43,17 +54,6 @@
 #define WLAN_SIR_perfect 10.0   // if SIR > 10dB, perfect reception
 #define WLAN_SIR_impossible 0.1 // if SIR < -10dB, impossible to receive
 
-/**
- * \ingroup wifi
- * \defgroup wifi-test wifi module tests
- */
-
-/**
- * \ingroup wifi-test
- * \ingroup tests
- *
- * \brief fn_parameter_t structure
- */
 typedef struct fn_parameter_t
 {
     double beta; ///< beta
@@ -284,3 +284,5 @@
     }
     return 0;
 }
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/block-ack-test-suite.cc ns-3.42/src/wifi/test/block-ack-test-suite.cc
--- ns-3.41/src/wifi/test/block-ack-test-suite.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/block-ack-test-suite.cc	2024-05-29 15:29:47.216073800 -0700
@@ -18,6 +18,7 @@
  */
 
 #include "ns3/ap-wifi-mac.h"
+#include "ns3/attribute-container.h"
 #include "ns3/boolean.h"
 #include "ns3/config.h"
 #include "ns3/ctrl-headers.h"
@@ -1903,6 +1904,14 @@
                 "BeaconGeneration",
                 BooleanValue(true));
 
+    if (m_txop)
+    {
+        // set the TXOP limit on BE AC
+        mac.SetEdca(AC_BE,
+                    "TxopLimits",
+                    AttributeContainerValue<TimeValue>(std::list{MicroSeconds(4800)}));
+    }
+
     NetDeviceContainer apDevices;
     apDevices = wifi.Install(phy, mac, wifiApNode);
 
@@ -1931,10 +1940,6 @@
         ptr.Get<QosTxop>()->TraceConnectWithoutContext(
             "TxopTrace",
             MakeCallback(&TxopDurationTracer::Trace, &txopTracer));
-
-        // set the TXOP limit on BE AC
-        ap_device->GetMac()->GetAttribute("BE_Txop", ptr);
-        ptr.Get<QosTxop>()->SetTxopLimit(MicroSeconds(4800));
     }
 
     PacketSocketAddress socket;
@@ -2018,17 +2023,17 @@
 };
 
 BlockAckTestSuite::BlockAckTestSuite()
-    : TestSuite("wifi-block-ack", UNIT)
+    : TestSuite("wifi-block-ack", Type::UNIT)
 {
-    AddTestCase(new PacketBufferingCaseA, TestCase::QUICK);
-    AddTestCase(new PacketBufferingCaseB, TestCase::QUICK);
-    AddTestCase(new OriginatorBlockAckWindowTest, TestCase::QUICK);
-    AddTestCase(new CtrlBAckResponseHeaderTest, TestCase::QUICK);
-    AddTestCase(new BlockAckRecipientBufferTest(0), TestCase::QUICK);
-    AddTestCase(new BlockAckRecipientBufferTest(4090), TestCase::QUICK);
-    AddTestCase(new MultiStaCtrlBAckResponseHeaderTest, TestCase::QUICK);
-    AddTestCase(new BlockAckAggregationDisabledTest(false), TestCase::QUICK);
-    AddTestCase(new BlockAckAggregationDisabledTest(true), TestCase::QUICK);
+    AddTestCase(new PacketBufferingCaseA, TestCase::Duration::QUICK);
+    AddTestCase(new PacketBufferingCaseB, TestCase::Duration::QUICK);
+    AddTestCase(new OriginatorBlockAckWindowTest, TestCase::Duration::QUICK);
+    AddTestCase(new CtrlBAckResponseHeaderTest, TestCase::Duration::QUICK);
+    AddTestCase(new BlockAckRecipientBufferTest(0), TestCase::Duration::QUICK);
+    AddTestCase(new BlockAckRecipientBufferTest(4090), TestCase::Duration::QUICK);
+    AddTestCase(new MultiStaCtrlBAckResponseHeaderTest, TestCase::Duration::QUICK);
+    AddTestCase(new BlockAckAggregationDisabledTest(false), TestCase::Duration::QUICK);
+    AddTestCase(new BlockAckAggregationDisabledTest(true), TestCase::Duration::QUICK);
 }
 
 static BlockAckTestSuite g_blockAckTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/channel-access-manager-test.cc ns-3.42/src/wifi/test/channel-access-manager-test.cc
--- ns-3.41/src/wifi/test/channel-access-manager-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/channel-access-manager-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -22,9 +22,11 @@
 #include "ns3/frame-exchange-manager.h"
 #include "ns3/interference-helper.h"
 #include "ns3/multi-model-spectrum-channel.h"
+#include "ns3/pointer.h"
 #include "ns3/qos-txop.h"
 #include "ns3/simulator.h"
 #include "ns3/spectrum-wifi-phy.h"
+#include "ns3/string.h"
 #include "ns3/test.h"
 
 #include <list>
@@ -638,7 +640,9 @@
     m_txop.push_back(txop);
     m_ChannelAccessManager->Add(txop);
     // the following causes the creation of a link for the txop object
-    auto mac = CreateObject<AdhocWifiMac>();
+    auto mac = CreateObjectWithAttributes<AdhocWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     mac->SetWifiPhys({nullptr});
     txop->SetWifiMac(mac);
     txop->SetAifsn(aifsn);
@@ -1538,9 +1542,9 @@
 };
 
 TxopTestSuite::TxopTestSuite()
-    : TestSuite("wifi-devices-dcf", UNIT)
+    : TestSuite("wifi-devices-dcf", Type::UNIT)
 {
-    AddTestCase(new ChannelAccessManagerTest<Txop>, TestCase::QUICK);
+    AddTestCase(new ChannelAccessManagerTest<Txop>, TestCase::Duration::QUICK);
 }
 
 static TxopTestSuite g_dcfTestSuite;
@@ -1558,9 +1562,9 @@
 };
 
 QosTxopTestSuite::QosTxopTestSuite()
-    : TestSuite("wifi-devices-edca", UNIT)
+    : TestSuite("wifi-devices-edca", Type::UNIT)
 {
-    AddTestCase(new ChannelAccessManagerTest<QosTxop>, TestCase::QUICK);
+    AddTestCase(new ChannelAccessManagerTest<QosTxop>, TestCase::Duration::QUICK);
 }
 
 static QosTxopTestSuite g_edcaTestSuite;
@@ -1578,9 +1582,9 @@
 };
 
 ChannelAccessManagerTestSuite::ChannelAccessManagerTestSuite()
-    : TestSuite("wifi-channel-access-manager", UNIT)
+    : TestSuite("wifi-channel-access-manager", Type::UNIT)
 {
-    AddTestCase(new LargestIdlePrimaryChannelTest, TestCase::QUICK);
+    AddTestCase(new LargestIdlePrimaryChannelTest, TestCase::Duration::QUICK);
 }
 
 static ChannelAccessManagerTestSuite g_camTestSuite;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/inter-bss-test-suite.cc ns-3.42/src/wifi/test/inter-bss-test-suite.cc
--- ns-3.41/src/wifi/test/inter-bss-test-suite.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/inter-bss-test-suite.cc	2024-05-29 15:29:47.216073800 -0700
@@ -339,17 +339,17 @@
                         ap_device2,
                         WifiPhyState::TX);
     // All other PHYs should have stay idle until 4us (preamble detection time).
-    Simulator::Schedule(Seconds(2.0) + MicroSeconds(13),
+    Simulator::Schedule(Seconds(2.0) + MicroSeconds(11),
                         &TestInterBssConstantObssPdAlgo::CheckPhyState,
                         this,
                         sta_device1,
                         WifiPhyState::IDLE);
-    Simulator::Schedule(Seconds(2.0) + MicroSeconds(13),
+    Simulator::Schedule(Seconds(2.0) + MicroSeconds(11),
                         &TestInterBssConstantObssPdAlgo::CheckPhyState,
                         this,
                         sta_device2,
                         WifiPhyState::IDLE);
-    Simulator::Schedule(Seconds(2.0) + MicroSeconds(13),
+    Simulator::Schedule(Seconds(2.0) + MicroSeconds(11),
                         &TestInterBssConstantObssPdAlgo::CheckPhyState,
                         this,
                         ap_device1,
@@ -997,10 +997,12 @@
 };
 
 InterBssTestSuite::InterBssTestSuite()
-    : TestSuite("wifi-inter-bss", UNIT)
+    : TestSuite("wifi-inter-bss", Type::UNIT)
 {
-    AddTestCase(new TestInterBssConstantObssPdAlgo(WIFI_STANDARD_80211ax), TestCase::QUICK);
-    AddTestCase(new TestInterBssConstantObssPdAlgo(WIFI_STANDARD_80211be), TestCase::QUICK);
+    AddTestCase(new TestInterBssConstantObssPdAlgo(WIFI_STANDARD_80211ax),
+                TestCase::Duration::QUICK);
+    AddTestCase(new TestInterBssConstantObssPdAlgo(WIFI_STANDARD_80211be),
+                TestCase::Duration::QUICK);
 }
 
 // Do not forget to allocate an instance of this TestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/power-rate-adaptation-test.cc ns-3.42/src/wifi/test/power-rate-adaptation-test.cc
--- ns-3.41/src/wifi/test/power-rate-adaptation-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/power-rate-adaptation-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -23,7 +23,9 @@
 #include "ns3/frame-exchange-manager.h"
 #include "ns3/interference-helper.h"
 #include "ns3/node.h"
+#include "ns3/pointer.h"
 #include "ns3/simulator.h"
+#include "ns3/string.h"
 #include "ns3/test.h"
 #include "ns3/wifi-default-ack-manager.h"
 #include "ns3/wifi-default-protection-manager.h"
@@ -115,11 +117,15 @@
     /*
      * Create mac layer. We use Adhoc because association is not needed to get supported rates.
      */
-    Ptr<AdhocWifiMac> mac = CreateObject<AdhocWifiMac>();
+    auto mac = CreateObjectWithAttributes<AdhocWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     mac->SetDevice(dev);
     mac->SetAddress(Mac48Address::Allocate());
     dev->SetMac(mac);
-    mac->ConfigureStandard(WIFI_STANDARD_80211a);
+    mac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    mac->SetFrameExchangeManagers({CreateObject<FrameExchangeManager>()});
+    mac->GetFrameExchangeManager(SINGLE_LINK_OP_ID)->SetAddress(mac->GetAddress());
     mac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
     Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager();
 
@@ -1168,9 +1174,9 @@
 };
 
 PowerRateAdaptationTestSuite::PowerRateAdaptationTestSuite()
-    : TestSuite("wifi-power-rate-adaptation", UNIT)
+    : TestSuite("wifi-power-rate-adaptation", Type::UNIT)
 {
-    AddTestCase(new PowerRateAdaptationTest, TestCase::QUICK);
+    AddTestCase(new PowerRateAdaptationTest, TestCase::Duration::QUICK);
 }
 
 static PowerRateAdaptationTestSuite g_powerRateAdaptationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/power-save-test.cc ns-3.42/src/wifi/test/power-save-test.cc
--- ns-3.41/src/wifi/test/power-save-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/test/power-save-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Davide Magrin <davide@magr.in>
+ */
+
+#include "ns3/assert.h"
+#include "ns3/header-serialization-test.h"
+#include "ns3/log.h"
+#include "ns3/test.h"
+#include "ns3/tim.h"
+
+#include <algorithm>
+#include <iterator>
+#include <list>
+#include <sstream>
+#include <vector>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("PowerSaveTest");
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief Test TIM Information element serialization and deserialization
+ */
+class TimInformationElementTest : public HeaderSerializationTestCase
+{
+  public:
+    /**
+     * \brief Constructor
+     */
+    TimInformationElementTest();
+
+    void DoRun() override;
+    /**
+     * Reset the passed TIM to have the provided parameters.
+     *
+     * \param tim the TIM element to set
+     * \param dtimCount the DTIM count value
+     * \param dtimPeriod the DTIM period value
+     * \param multicastPending whether group addressed frames are queued
+     * \param aidValues the AID values to set
+     */
+    void SetTim(Tim& tim,
+                uint8_t dtimCount,
+                uint8_t dtimPeriod,
+                bool multicastPending,
+                const std::list<uint16_t>& aidValues);
+
+    /**
+     * Test that the Bitmap Control and the Partial Virtual Bitmap
+     * fields of the provided TIM match the passed bufferContents.
+     *
+     * \param tim the provided TIM
+     * \param bufferContents the expected content of the buffer
+     */
+    void CheckSerializationAgainstBuffer(Tim& tim, const std::vector<uint8_t>& bufferContents);
+
+    /**
+     * Test that the GetAidSet() method return the expected set of AID values.
+     *
+     * \param tim the TIM element
+     * \param aid the AID value passed to GetAidSet()
+     * \param expectedSet the expected set of AID values returned by GetAidSet()
+     */
+    void CheckAidSet(const Tim& tim, uint16_t aid, const std::set<uint16_t>& expectedSet);
+};
+
+TimInformationElementTest::TimInformationElementTest()
+    : HeaderSerializationTestCase("Test for the TIM Information Element implementation")
+{
+}
+
+void
+TimInformationElementTest::SetTim(Tim& tim,
+                                  uint8_t dtimCount,
+                                  uint8_t dtimPeriod,
+                                  bool multicastPending,
+                                  const std::list<uint16_t>& aidValues)
+{
+    tim = Tim();
+    tim.m_dtimCount = dtimCount;
+    tim.m_dtimPeriod = dtimPeriod;
+    tim.m_hasMulticastPending = multicastPending;
+    tim.AddAid(aidValues.begin(), aidValues.end());
+}
+
+void
+TimInformationElementTest::CheckSerializationAgainstBuffer(
+    Tim& tim,
+    const std::vector<uint8_t>& bufferContents)
+{
+    // Serialize the TIM
+    Buffer buffer;
+    buffer.AddAtStart(tim.GetSerializedSize());
+    tim.Serialize(buffer.Begin());
+
+    // Check the two Buffer instances
+    Buffer::Iterator bufferIterator = buffer.Begin();
+    for (uint32_t j = 0; j < buffer.GetSize(); j++)
+    {
+        // We skip the first four bytes, since they contain known information
+        if (j > 3)
+        {
+            NS_TEST_EXPECT_MSG_EQ(bufferIterator.ReadU8(),
+                                  bufferContents.at(j - 4),
+                                  "Serialization is different than provided known serialization");
+        }
+        else
+        {
+            // Advance the serialized buffer, which also contains
+            // the Element ID, Length, DTIM Count, DTIM Period fields
+            bufferIterator.ReadU8();
+        }
+    }
+}
+
+void
+TimInformationElementTest::CheckAidSet(const Tim& tim,
+                                       uint16_t aid,
+                                       const std::set<uint16_t>& expectedSet)
+{
+    auto ret = tim.GetAidSet(aid);
+
+    {
+        std::vector<uint16_t> diff;
+
+        // Expected set minus returned set provides expected elements that are not returned
+        std::set_difference(expectedSet.cbegin(),
+                            expectedSet.cend(),
+                            ret.cbegin(),
+                            ret.cend(),
+                            std::back_inserter(diff));
+
+        std::stringstream ss;
+        std::copy(diff.cbegin(), diff.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+
+        NS_TEST_EXPECT_MSG_EQ(diff.size(),
+                              0,
+                              "Expected elements not returned by GetAidSet(): " << ss.str());
+    }
+    {
+        std::vector<uint16_t> diff;
+
+        // Returned set minus expected set provides returned elements that are not expected
+        std::set_difference(ret.cbegin(),
+                            ret.cend(),
+                            expectedSet.cbegin(),
+                            expectedSet.cend(),
+                            std::back_inserter(diff));
+
+        std::stringstream ss;
+        std::copy(diff.cbegin(), diff.cend(), std::ostream_iterator<uint16_t>(ss, " "));
+
+        NS_TEST_EXPECT_MSG_EQ(diff.size(),
+                              0,
+                              "Returned elements not expected by GetAidSet(): " << ss.str());
+    }
+}
+
+void
+TimInformationElementTest::DoRun()
+{
+    Tim tim;
+
+    // The first three examples from 802.11-2020, Annex L
+    //
+    // 1. No group addressed MSDUs, but there is traffic for STAs with AID 2 and AID 7
+    SetTim(tim, 0, 3, false, {2, 7});
+    TestHeaderSerialization(tim);
+    CheckSerializationAgainstBuffer(tim, {0b00000000, 0b10000100});
+    CheckAidSet(tim, 0, {2, 7});
+    CheckAidSet(tim, 1, {2, 7});
+    CheckAidSet(tim, 2, {7});
+    CheckAidSet(tim, 7, {});
+    //
+    // 2. There are group addressed MSDUs, DTIM count = 0, the nodes
+    // with AID 2, 7, 22, and 24 have data buffered in the AP
+    SetTim(tim, 0, 3, true, {2, 7, 22, 24});
+    TestHeaderSerialization(tim);
+    CheckSerializationAgainstBuffer(tim,
+                                    {
+                                        0b00000001,
+                                        // NOTE The following byte is different from the example
+                                        // in the standard. This is because the example sets the
+                                        // AID 0 bit in the partial virtual bitmap to 1. Our code
+                                        // and the example code provided in the Annex, instead, do
+                                        // not set this bit. Relevant Note from 802.11-2020,
+                                        // Section 9.4.2.5.1: "The bit numbered 0 in the traffic
+                                        // indication virtual bitmap need not be included in the
+                                        // Partial Virtual Bitmap field even if that bit is set."
+                                        0b10000100,
+                                        0b00000000,
+                                        0b01000000,
+                                        0b00000001,
+                                    });
+    CheckAidSet(tim, 0, {2, 7, 22, 24});
+    CheckAidSet(tim, 2, {7, 22, 24});
+    CheckAidSet(tim, 7, {22, 24});
+    CheckAidSet(tim, 22, {24});
+    CheckAidSet(tim, 24, {});
+    //
+    // 3. There are group addressed MSDUs, DTIM count = 0, only the node
+    // with AID 24 has data buffered in the AP
+    SetTim(tim, 0, 3, true, {24});
+    TestHeaderSerialization(tim);
+    CheckSerializationAgainstBuffer(tim, {0b00000011, 0b00000000, 0b00000001});
+
+    // Other arbitrary examples just to make sure
+    // Serialization -> Deserialization -> Serialization works
+    SetTim(tim, 0, 3, false, {2000});
+    TestHeaderSerialization(tim);
+    SetTim(tim, 1, 3, true, {1, 134});
+    TestHeaderSerialization(tim);
+    SetTim(tim, 1, 3, false, {1, 2});
+    TestHeaderSerialization(tim);
+
+    // Edge cases
+    //
+    // What if there is group addressed data only?
+    //
+    // In this case, we should still have an empty byte in the Partial Virtual Bitmap.
+    // From 802.11-2020: in the event that all bits other than bit 0 in the traffic indication
+    // virtual bitmap are 0, the Partial Virtual Bitmap field is encoded as a single octet
+    // equal to 0, the Bitmap Offset subfield is 0, and the Length field is 4.
+    SetTim(tim, 0, 3, true, {});
+    TestHeaderSerialization(tim);
+    CheckSerializationAgainstBuffer(tim, {0b00000001, 0b00000000});
+    NS_TEST_EXPECT_MSG_EQ(tim.GetSerializedSize() - 2, 4, "Unexpected TIM Length");
+    //
+    // What if there is no group addressed data and no unicast data?
+    //
+    // From 802.11-2020: When the TIM is carried in a non-S1G PPDU, in the event that all bits
+    // other than bit 0 in the traffic indication virtual bitmap are 0, the Partial Virtual Bitmap
+    // field is encoded as a single octet equal to 0, the Bitmap Offset subfield is 0, and the
+    // Length field is 4.
+    SetTim(tim, 0, 3, false, {});
+    TestHeaderSerialization(tim);
+    CheckSerializationAgainstBuffer(tim, {0b00000000, 0b00000000});
+    NS_TEST_EXPECT_MSG_EQ(tim.GetSerializedSize() - 2, 4, "Unexpected TIM Length");
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief Power Save Test Suite
+ */
+class PowerSaveTestSuite : public TestSuite
+{
+  public:
+    PowerSaveTestSuite();
+};
+
+PowerSaveTestSuite::PowerSaveTestSuite()
+    : TestSuite("wifi-power-save", Type::UNIT)
+{
+    AddTestCase(new TimInformationElementTest, TestCase::Duration::QUICK);
+}
+
+static PowerSaveTestSuite g_powerSaveTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/spectrum-wifi-phy-test.cc ns-3.42/src/wifi/test/spectrum-wifi-phy-test.cc
--- ns-3.41/src/wifi/test/spectrum-wifi-phy-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/spectrum-wifi-phy-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -20,6 +20,7 @@
 #include "ns3/he-phy.h" //includes OFDM PHY
 #include "ns3/interference-helper.h"
 #include "ns3/log.h"
+#include "ns3/mobility-helper.h"
 #include "ns3/multi-model-spectrum-channel.h"
 #include "ns3/nist-error-rate-model.h"
 #include "ns3/ofdm-ppdu.h"
@@ -38,6 +39,7 @@
 #include "ns3/wifi-utils.h"
 
 #include <memory>
+#include <optional>
 #include <tuple>
 #include <vector>
 
@@ -56,11 +58,44 @@
 class ExtSpectrumWifiPhy : public SpectrumWifiPhy
 {
   public:
-    using SpectrumWifiPhy::SpectrumWifiPhy;
     using WifiPhy::GetBand;
 };
 
 /**
+ * Extended InterferenceHelper class for the purpose of the tests.
+ */
+class ExtInterferenceHelper : public InterferenceHelper
+{
+  public:
+    /**
+     * \brief Get the type ID.
+     * \return the object TypeId
+     */
+    static TypeId GetTypeId()
+    {
+        static TypeId tid = TypeId("ns3::ExtInterferenceHelper")
+                                .SetParent<InterferenceHelper>()
+                                .SetGroupName("Wifi")
+                                .AddConstructor<ExtInterferenceHelper>();
+        return tid;
+    }
+
+    /**
+     * Indicate whether the interference helper is in receiving state
+     *
+     * \return true if the interference helper is in receiving state, false otherwise
+     */
+    bool IsRxing() const
+    {
+        return std::any_of(m_rxing.cbegin(), m_rxing.cend(), [](const auto& rxing) {
+            return rxing.second;
+        });
+    }
+};
+
+NS_OBJECT_ENSURE_REGISTERED(ExtInterferenceHelper);
+
+/**
  * \ingroup wifi-test
  * \ingroup tests
  *
@@ -789,13 +824,22 @@
 class SpectrumWifiPhyMultipleInterfacesTest : public TestCase
 {
   public:
+    /// Enumeration for channel switching scenarios
+    enum class ChannelSwitchScenario : uint8_t
+    {
+        BEFORE_TX = 0, //!< start TX after channel switch is completed
+        BETWEEN_TX_RX  //!< perform channel switch during propagation delay (after TX and before RX)
+    };
+
     /**
      * Constructor
      *
      * \param trackSignalsInactiveInterfaces flag to indicate whether signals coming from inactive
      * spectrum PHY interfaces shall be tracked during the test
+     * \param chanSwitchScenario the channel switching scenario to consider for the test
      */
-    SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces);
+    SpectrumWifiPhyMultipleInterfacesTest(bool trackSignalsInactiveInterfaces,
+                                          ChannelSwitchScenario chanSwitchScenario);
 
   private:
     void DoSetup() override;
@@ -805,15 +849,17 @@
     /**
      * Switch channel function
      *
-     * \param index the index to identify the RX PHY
+     * \param phy the PHY to switch
      * \param band the PHY band to use
      * \param channelNumber number the channel number to use
      * \param channelWidth the channel width to use
+     * \param listenerIndex index of the listener for that PHY, if PHY is a RX PHY
      */
-    void SwitchChannel(std::size_t index,
+    void SwitchChannel(Ptr<SpectrumWifiPhy> phy,
                        WifiPhyBand band,
                        uint8_t channelNumber,
-                       uint16_t channelWidth);
+                       uint16_t channelWidth,
+                       std::optional<std::size_t> listenerIndex);
 
     /**
      * Send PPDU function
@@ -821,8 +867,9 @@
      * \param phy the PHY to transmit the signal
      * \param txPowerDbm the power in dBm to transmit the signal (this is also the received power
      * since we do not have propagation loss to simplify)
+     * \param payloadSize the payload size in bytes
      */
-    void SendPpdu(Ptr<SpectrumWifiPhy> phy, double txPowerDbm);
+    void SendPpdu(Ptr<SpectrumWifiPhy> phy, double txPowerDbm, uint32_t payloadSize);
 
     /**
      * Callback triggered when a packet is received by a PHY
@@ -835,6 +882,27 @@
                     RxPowerWattPerChannelBand rxPowersW);
 
     /**
+     * Receive success function
+     * \param index index of the RX STA
+     * \param psdu the PSDU
+     * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
+     * \param txVector the transmit vector
+     * \param statusPerMpdu reception status per MPDU
+     */
+    void RxSuccess(std::size_t index,
+                   Ptr<const WifiPsdu> psdu,
+                   RxSignalInfo rxSignalInfo,
+                   WifiTxVector txVector,
+                   std::vector<bool> statusPerMpdu);
+
+    /**
+     * Receive failure function
+     * \param index index of the RX STA
+     * \param psdu the PSDU
+     */
+    void RxFailure(std::size_t index, Ptr<const WifiPsdu> psdu);
+
+    /**
      * Schedule now to check the interferences
      * \param phy the PHY for which the check has to be executed
      * \param freqRange the frequency range for which the check has to be executed
@@ -861,6 +929,8 @@
      *
      * \param index the index to identify the RX PHY to check
      * \param expectedNumRx the expected number of RX events for that PHY
+     * \param expectedNumRxSuccess the expected amount of successfully received packets
+     * \param expectedRxBytes the expected amount of received bytes
      * \param expectedFrequencyRangeActiveRfInterface the expected frequency range (in MHz) of the
      * active RF interface
      * \param expectedConnectedPhysPerChannel the expected
@@ -868,6 +938,8 @@
      */
     void CheckResults(std::size_t index,
                       uint32_t expectedNumRx,
+                      uint32_t expectedNumRxSuccess,
+                      uint32_t expectedRxBytes,
                       FrequencyRange expectedFrequencyRangeActiveRfInterface,
                       const std::vector<std::size_t>& expectedConnectedPhysPerChannel);
 
@@ -878,8 +950,21 @@
      * \param expectedCcaBusyIndication flag to indicate whether a CCA BUSY notification is expected
      * \param switchingDelay delay between the TX has started and the time RX switched to the TX
      * channel
+     * \param propagationDelay the propagation delay
+     */
+    void CheckCcaIndication(std::size_t index,
+                            bool expectedCcaBusyIndication,
+                            Time switchingDelay,
+                            Time propagationDelay);
+
+    /**
+     * Verify rxing state of the interference helper
+     *
+     * \param phy the PHY to which the interference helper instance is attached
+     * \param rxingExpected flag whether the interference helper is expected to be in rxing state or
+     * not
      */
-    void CheckCcaIndication(std::size_t index, bool expectedCcaBusyIndication, Time switchingDelay);
+    void CheckRxingState(Ptr<SpectrumWifiPhy> phy, bool rxingExpected);
 
     /**
      * Reset function
@@ -889,49 +974,67 @@
     bool
         m_trackSignalsInactiveInterfaces; //!< flag to indicate whether signals coming from inactive
                                           //!< spectrum PHY interfaces are tracked during the test
-
+    ChannelSwitchScenario
+        m_chanSwitchScenario; //!< the channel switch scenario to consider for the test
     std::vector<Ptr<MultiModelSpectrumChannel>> m_spectrumChannels; //!< Spectrum channels
     std::vector<Ptr<SpectrumWifiPhy>> m_txPhys{};                   //!< TX PHYs
     std::vector<Ptr<SpectrumWifiPhy>> m_rxPhys{};                   //!< RX PHYs
     std::vector<std::shared_ptr<TestPhyListener>> m_listeners{};    //!< listeners
 
-    std::vector<uint32_t> m_counts{0}; //!< count number of packets received by PHYs
+    std::vector<uint32_t> m_counts; //!< count number of packets received by PHYs
+    std::vector<uint32_t>
+        m_countRxSuccess; //!< count number of packets successfully received by PHYs
+    std::vector<uint32_t>
+        m_countRxFailure;            //!< count number of packets unsuccessfully received by PHYs
+    std::vector<uint32_t> m_rxBytes; //!< count number of received bytes
 
     Time m_lastTxStart{0}; //!< hold the time at which the last transmission started
     Time m_lastTxEnd{0};   //!< hold the time at which the last transmission ended
 };
 
 SpectrumWifiPhyMultipleInterfacesTest::SpectrumWifiPhyMultipleInterfacesTest(
-    bool trackSignalsInactiveInterfaces)
+    bool trackSignalsInactiveInterfaces,
+    ChannelSwitchScenario chanSwitchScenario)
     : TestCase{"SpectrumWifiPhy test operation with multiple RF interfaces"},
-      m_trackSignalsInactiveInterfaces{trackSignalsInactiveInterfaces}
+      m_trackSignalsInactiveInterfaces{trackSignalsInactiveInterfaces},
+      m_chanSwitchScenario{chanSwitchScenario}
 {
 }
 
 void
-SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel(std::size_t index,
+SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel(Ptr<SpectrumWifiPhy> phy,
                                                      WifiPhyBand band,
                                                      uint8_t channelNumber,
-                                                     uint16_t channelWidth)
+                                                     uint16_t channelWidth,
+                                                     std::optional<std::size_t> listenerIndex)
 {
-    NS_LOG_FUNCTION(this << index << band << +channelNumber << channelWidth);
-    auto& listener = m_listeners.at(index);
-    listener->m_notifyMaybeCcaBusyStart = 0;
-    listener->m_ccaBusyStart = Seconds(0);
-    listener->m_ccaBusyEnd = Seconds(0);
-    auto phy = m_rxPhys.at(index);
+    NS_LOG_FUNCTION(this << phy << band << +channelNumber << channelWidth);
+    if (listenerIndex)
+    {
+        auto& listener = m_listeners.at(*listenerIndex);
+        listener->m_notifyMaybeCcaBusyStart = 0;
+        listener->m_ccaBusyStart = Seconds(0);
+        listener->m_ccaBusyEnd = Seconds(0);
+    }
     phy->SetOperatingChannel(WifiPhy::ChannelTuple{channelNumber, channelWidth, band, 0});
+    // verify rxing state of interference helper is reset after channel switch
+    Simulator::ScheduleNow(&SpectrumWifiPhyMultipleInterfacesTest::CheckRxingState,
+                           this,
+                           phy,
+                           false);
 }
 
 void
-SpectrumWifiPhyMultipleInterfacesTest::SendPpdu(Ptr<SpectrumWifiPhy> phy, double txPowerDbm)
+SpectrumWifiPhyMultipleInterfacesTest::SendPpdu(Ptr<SpectrumWifiPhy> phy,
+                                                double txPowerDbm,
+                                                uint32_t payloadSize)
 {
-    NS_LOG_FUNCTION(this << phy << txPowerDbm << phy->GetCurrentFrequencyRange()
+    NS_LOG_FUNCTION(this << phy << txPowerDbm << payloadSize << phy->GetCurrentFrequencyRange()
                          << phy->GetChannelWidth() << phy->GetChannelNumber());
 
     WifiTxVector txVector =
-        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, false, false);
-    Ptr<Packet> pkt = Create<Packet>(1000);
+        WifiTxVector(HePhy::GetHeMcs11(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, false, false);
+    Ptr<Packet> pkt = Create<Packet>(payloadSize);
     WifiMacHeader hdr;
     hdr.SetType(WIFI_MAC_QOSDATA);
     hdr.SetQosTid(0);
@@ -950,13 +1053,33 @@
 
 void
 SpectrumWifiPhyMultipleInterfacesTest::RxCallback(std::size_t index,
-                                                  Ptr<const Packet> /*packet*/,
+                                                  Ptr<const Packet> packet,
                                                   RxPowerWattPerChannelBand /*rxPowersW*/)
 {
     auto phy = m_rxPhys.at(index);
-    NS_LOG_FUNCTION(this << index << phy->GetCurrentFrequencyRange() << phy->GetChannelWidth()
-                         << phy->GetChannelNumber());
+    const auto payloadBytes = packet->GetSize() - 30;
+    NS_LOG_FUNCTION(this << index << payloadBytes << phy->GetCurrentFrequencyRange()
+                         << phy->GetChannelWidth() << phy->GetChannelNumber());
     m_counts.at(index)++;
+    m_rxBytes.at(index) += payloadBytes;
+}
+
+void
+SpectrumWifiPhyMultipleInterfacesTest::RxSuccess(std::size_t index,
+                                                 Ptr<const WifiPsdu> psdu,
+                                                 RxSignalInfo rxSignalInfo,
+                                                 WifiTxVector txVector,
+                                                 std::vector<bool> /*statusPerMpdu*/)
+{
+    NS_LOG_FUNCTION(this << index << *psdu << rxSignalInfo << txVector);
+    m_countRxSuccess.at(index)++;
+}
+
+void
+SpectrumWifiPhyMultipleInterfacesTest::RxFailure(std::size_t index, Ptr<const WifiPsdu> psdu)
+{
+    NS_LOG_FUNCTION(this << index << *psdu);
+    m_countRxFailure.at(index)++;
 }
 
 void
@@ -999,10 +1122,13 @@
 SpectrumWifiPhyMultipleInterfacesTest::CheckResults(
     std::size_t index,
     uint32_t expectedNumRx,
+    uint32_t expectedNumRxSuccess,
+    uint32_t expectedRxBytes,
     FrequencyRange expectedFrequencyRangeActiveRfInterface,
     const std::vector<std::size_t>& expectedConnectedPhysPerChannel)
 {
-    NS_LOG_FUNCTION(this << index << expectedNumRx << expectedFrequencyRangeActiveRfInterface);
+    NS_LOG_FUNCTION(this << index << expectedNumRx << expectedNumRxSuccess << expectedRxBytes
+                         << expectedFrequencyRangeActiveRfInterface);
     const auto phy = m_rxPhys.at(index);
     std::size_t numActiveInterfaces = 0;
     for (const auto& [freqRange, interface] : phy->GetSpectrumPhyInterfaces())
@@ -1023,22 +1149,28 @@
                               expectedConnectedPhysPerChannel.at(i),
                               "Incorrect number of PHYs attached to the spectrum channel");
     }
-    NS_TEST_ASSERT_MSG_EQ(m_counts.at(index),
-                          expectedNumRx,
-                          "Didn't receive right number of packets");
+    NS_TEST_ASSERT_MSG_EQ(m_counts.at(index), expectedNumRx, "Unexpected amount of RX events");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxSuccess.at(index),
+                          expectedNumRxSuccess,
+                          "Unexpected amount of successfully received packets");
+    NS_TEST_ASSERT_MSG_EQ(m_countRxFailure.at(index),
+                          0,
+                          "Unexpected amount of unsuccessfully received packets");
     NS_TEST_ASSERT_MSG_EQ(m_listeners.at(index)->m_notifyRxStart,
-                          expectedNumRx,
-                          "Didn't receive NotifyRxStart");
+                          expectedNumRxSuccess,
+                          "Unexpected amount of RX payload start indication");
 }
 
 void
 SpectrumWifiPhyMultipleInterfacesTest::CheckCcaIndication(std::size_t index,
                                                           bool expectedCcaBusyIndication,
-                                                          Time switchingDelay)
+                                                          Time switchingDelay,
+                                                          Time propagationDelay)
 {
     const auto expectedCcaBusyStart =
         expectedCcaBusyIndication ? m_lastTxStart + switchingDelay : Seconds(0);
-    const auto expectedCcaBusyEnd = expectedCcaBusyIndication ? m_lastTxEnd : Seconds(0);
+    const auto expectedCcaBusyEnd =
+        expectedCcaBusyIndication ? m_lastTxEnd + propagationDelay : Seconds(0);
     NS_LOG_FUNCTION(this << index << expectedCcaBusyIndication << expectedCcaBusyStart
                          << expectedCcaBusyEnd);
     auto& listener = m_listeners.at(index);
@@ -1053,6 +1185,17 @@
 }
 
 void
+SpectrumWifiPhyMultipleInterfacesTest::CheckRxingState(Ptr<SpectrumWifiPhy> phy, bool rxingExpected)
+{
+    NS_LOG_FUNCTION(this << phy << rxingExpected);
+    PointerValue ptr;
+    phy->GetAttribute("InterferenceHelper", ptr);
+    auto interferenceHelper = DynamicCast<ExtInterferenceHelper>(ptr.Get<ExtInterferenceHelper>());
+    NS_ASSERT(interferenceHelper);
+    NS_TEST_ASSERT_MSG_EQ(interferenceHelper->IsRxing(), rxingExpected, "Incorrect rxing state");
+}
+
+void
 SpectrumWifiPhyMultipleInterfacesTest::Reset()
 {
     NS_LOG_FUNCTION(this);
@@ -1068,10 +1211,24 @@
     for (std::size_t rxPhyIndex = 0; rxPhyIndex < m_rxPhys.size(); ++rxPhyIndex)
     {
         auto txPhy = m_txPhys.at(rxPhyIndex);
-        SwitchChannel(rxPhyIndex,
+        SwitchChannel(m_rxPhys.at(rxPhyIndex),
                       txPhy->GetPhyBand(),
                       txPhy->GetChannelNumber(),
-                      txPhy->GetChannelWidth());
+                      txPhy->GetChannelWidth(),
+                      rxPhyIndex);
+    }
+    // reset counters
+    for (auto& countRxSuccess : m_countRxSuccess)
+    {
+        countRxSuccess = 0;
+    }
+    for (auto& countRxFailure : m_countRxFailure)
+    {
+        countRxFailure = 0;
+    }
+    for (auto& rxBytes : m_rxBytes)
+    {
+        rxBytes = 0;
     }
 }
 
@@ -1090,6 +1247,7 @@
     wifi.SetStandard(WIFI_STANDARD_80211be);
 
     SpectrumWifiPhyHelper phyHelper(4);
+    phyHelper.SetInterferenceHelper("ns3::ExtInterferenceHelper");
     phyHelper.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
 
     struct SpectrumPhyInterfaceInfo
@@ -1125,6 +1283,8 @@
                                                  WIFI_STANDARD_80211be,
                                                  interfaces.at(i).band));
 
+        auto delayModel = CreateObject<ConstantSpeedPropagationDelayModel>();
+        spectrumChannel->SetPropagationDelayModel(delayModel);
         std::ostringstream oss;
         oss << "{" << +interfaces.at(i).number << ", 0, " << interfaces.at(i).bandName << ", 0}";
         phyHelper.Set(i, "ChannelSettings", StringValue(oss.str()));
@@ -1143,25 +1303,52 @@
                   BooleanValue(m_trackSignalsInactiveInterfaces));
     auto staDevice = wifi.Install(phyHelper, mac, wifiStaNode.Get(0));
 
+    MobilityHelper mobility;
+    auto positionAlloc = CreateObject<ListPositionAllocator>();
+
+    positionAlloc->Add(Vector(0.0, 0.0, 0.0));
+    positionAlloc->Add(Vector(10.0, 0.0, 0.0));
+    mobility.SetPositionAllocator(positionAlloc);
+
+    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+    mobility.Install(wifiApNode);
+    mobility.Install(wifiStaNode);
+
     for (std::size_t i = 0; i < interfaces.size(); ++i)
     {
         auto txPhy =
             DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(apDevice.Get(0))->GetPhy(i));
+        if (m_chanSwitchScenario == ChannelSwitchScenario::BETWEEN_TX_RX)
+        {
+            txPhy->SetAttribute("ChannelSwitchDelay", TimeValue(NanoSeconds(1)));
+        }
         m_txPhys.push_back(txPhy);
 
         const auto index = m_rxPhys.size();
         auto rxPhy =
             DynamicCast<SpectrumWifiPhy>(DynamicCast<WifiNetDevice>(staDevice.Get(0))->GetPhy(i));
+        if (m_chanSwitchScenario == ChannelSwitchScenario::BETWEEN_TX_RX)
+        {
+            rxPhy->SetAttribute("ChannelSwitchDelay", TimeValue(NanoSeconds(1)));
+        }
         rxPhy->TraceConnectWithoutContext(
             "PhyRxBegin",
             MakeCallback(&SpectrumWifiPhyMultipleInterfacesTest::RxCallback, this).Bind(index));
 
+        rxPhy->SetReceiveOkCallback(
+            MakeCallback(&SpectrumWifiPhyMultipleInterfacesTest::RxSuccess, this).Bind(index));
+        rxPhy->SetReceiveErrorCallback(
+            MakeCallback(&SpectrumWifiPhyMultipleInterfacesTest::RxFailure, this).Bind(index));
+
         auto listener = std::make_shared<TestPhyListener>();
         rxPhy->RegisterListener(listener);
         m_listeners.push_back(std::move(listener));
 
         m_rxPhys.push_back(rxPhy);
         m_counts.push_back(0);
+        m_countRxSuccess.push_back(0);
+        m_countRxFailure.push_back(0);
+        m_rxBytes.push_back(0);
     }
 }
 
@@ -1189,8 +1376,10 @@
 
     const auto ccaEdThresholdDbm = -62.0; ///< CCA-ED threshold in dBm
     const auto txAfterChannelSwitchDelay =
-        Seconds(0.25); ///< delay in seconds between channel switch is triggered and a transmission
-                       ///< gets started
+        MicroSeconds((m_chanSwitchScenario == ChannelSwitchScenario::BEFORE_TX)
+                         ? 250
+                         : 0); ///< delay in seconds between channel switch is triggered and a
+                               ///< transmission gets started
     const auto checkResultsDelay =
         Seconds(0.5); ///< delay in seconds between start of test and moment results are verified
     const auto flushResultsDelay =
@@ -1198,6 +1387,7 @@
     const auto txOngoingAfterTxStartedDelay =
         MicroSeconds(50); ///< delay in microseconds between a transmission has started and a point
                           ///< in time the transmission is ongoing
+    const auto propagationDelay = NanoSeconds(33); // propagation delay for the test scenario
 
     Time delay{0};
 
@@ -1208,6 +1398,7 @@
                                            // interferences on inactive interfaces
             std::vector<std::size_t>{2, 2, 2, 2}; // default channels active for all PHYs: each PHY
                                                   // only receives from its associated TX
+
     for (std::size_t i = 0; i < 4; ++i)
     {
         auto txPpduPhy = m_txPhys.at(i);
@@ -1216,7 +1407,8 @@
                             &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
                             this,
                             txPpduPhy,
-                            0);
+                            0,
+                            1000);
         for (std::size_t j = 0; j < 4; ++j)
         {
             auto txPhy = m_txPhys.at(j);
@@ -1234,6 +1426,8 @@
                                 this,
                                 j,
                                 (i == j) ? 1 : 0,
+                                (i == j) ? 1 : 0,
+                                (i == j) ? 1000 : 0,
                                 expectedFreqRange,
                                 expectedConnectedPhysPerChannel);
         }
@@ -1251,7 +1445,8 @@
                             &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
                             this,
                             txPpduPhy,
-                            0);
+                            0,
+                            1000);
         const auto& expectedFreqRange = txPpduPhy->GetCurrentFrequencyRange();
         for (std::size_t j = 0; j < 4; ++j)
         {
@@ -1266,10 +1461,11 @@
             Simulator::Schedule(delay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
                                 this,
-                                j,
+                                rxPhy,
                                 txPpduPhy->GetPhyBand(),
                                 txPpduPhy->GetChannelNumber(),
-                                txPpduPhy->GetChannelWidth());
+                                txPpduPhy->GetChannelWidth(),
+                                j);
             Simulator::Schedule(delay + txAfterChannelSwitchDelay + txOngoingAfterTxStartedDelay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::CheckInterferences,
                                 this,
@@ -1282,6 +1478,8 @@
                                 this,
                                 j,
                                 1,
+                                1,
+                                1000,
                                 expectedFreqRange,
                                 expectedConnectedPhysPerChannel);
         }
@@ -1303,7 +1501,8 @@
                             &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
                             this,
                             txPpduPhy,
-                            0);
+                            0,
+                            1000);
         for (std::size_t j = 0; j < 4; ++j)
         {
             if (!m_trackSignalsInactiveInterfaces)
@@ -1317,15 +1516,18 @@
             Simulator::Schedule(delay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
                                 this,
-                                j,
+                                m_rxPhys.at(j),
                                 WIFI_PHY_BAND_5GHZ,
                                 CHANNEL_NUMBER,
-                                CHANNEL_WIDTH);
+                                CHANNEL_WIDTH,
+                                j);
             Simulator::Schedule(delay + checkResultsDelay,
                                 &SpectrumWifiPhyMultipleInterfacesTest::CheckResults,
                                 this,
                                 j,
                                 (i == secondSpectrumChannelIndex) ? 1 : 0,
+                                (i == secondSpectrumChannelIndex) ? 1 : 0,
+                                (i == secondSpectrumChannelIndex) ? 1000 : 0,
                                 expectedFreqRange,
                                 expectedConnectedPhysPerChannel);
         }
@@ -1362,14 +1564,16 @@
                                         &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
                                         this,
                                         txPpduPhy,
-                                        txPowerDbm);
+                                        txPowerDbm,
+                                        1000);
                     Simulator::Schedule(delay + txOngoingAfterTxStartedDelay,
                                         &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
                                         this,
-                                        j,
+                                        m_rxPhys.at(j),
                                         band,
                                         channel,
-                                        channelWidth);
+                                        channelWidth,
+                                        j);
                     for (std::size_t k = 0; k < 4; ++k)
                     {
                         if ((i != j) && (k == i))
@@ -1387,7 +1591,8 @@
                             this,
                             k,
                             expectCcaBusyIndication,
-                            txOngoingAfterTxStartedDelay);
+                            txOngoingAfterTxStartedDelay,
+                            propagationDelay);
                     }
                     Simulator::Schedule(delay + flushResultsDelay,
                                         &SpectrumWifiPhyMultipleInterfacesTest::Reset,
@@ -1397,7 +1602,208 @@
         }
     }
 
-    Simulator::Stop(Seconds(30));
+    if (m_trackSignalsInactiveInterfaces)
+    {
+        /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet.
+         * Then, the PHY switches to another band where it starts receiving another packet.
+         * During reception of the PHY header, the PHY switches back to the initial band and starts
+         * receiving yet another packet. In this case, first and last packets should be successfully
+         * received (no interference), the second packet reception has been interrupted (before the
+         * payload reception does start, hence it does not reach the RX state). */
+        {
+            // first TX on initial band
+            auto txPpduPhy = m_txPhys.at(0);
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                20,
+                                500);
+
+            // switch channel to other band
+            delay += Seconds(1);
+            txPpduPhy = m_txPhys.at(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_rxPhys.at(0),
+                                txPpduPhy->GetPhyBand(),
+                                txPpduPhy->GetChannelNumber(),
+                                txPpduPhy->GetChannelWidth(),
+                                0);
+
+            // TX on other band
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                0,
+                                1000);
+
+            // switch back to initial band during PHY header reception
+            txPpduPhy = m_txPhys.at(0);
+            delay += MicroSeconds(20); // right after legacy PHY header reception
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_rxPhys.at(0),
+                                txPpduPhy->GetPhyBand(),
+                                txPpduPhy->GetChannelNumber(),
+                                txPpduPhy->GetChannelWidth(),
+                                0);
+
+            // TX once more on the initial band
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                0,
+                                1500);
+
+            // check results
+            Simulator::Schedule(
+                delay + checkResultsDelay,
+                &SpectrumWifiPhyMultipleInterfacesTest::CheckResults,
+                this,
+                0,
+                3,    // 3 RX events
+                2,    // 2 packets should have been successfully received, 1 packet should
+                      // have been interrupted (switch during PHY header reception)
+                2000, // 500 bytes (firstpacket) and 1500 bytes (third packet)
+                txPpduPhy->GetCurrentFrequencyRange(),
+                expectedConnectedPhysPerChannel);
+
+            // reset
+            Simulator::Schedule(delay + flushResultsDelay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::Reset,
+                                this);
+        }
+
+        /* Reproduce an EMLSR scenario where a PHY is on an initial band and receives a packet
+         * but switches to another band during preamble detection period. Then, it starts receiving
+         * two packets which interfere with each other. Afterwards, the PHY goes back to its initial
+         * band and starts receiving yet another packet. In this case, only the last packet should
+         * be successfully received (no interference). */
+        {
+            // switch channel of PHY index 0 to 5 GHz low band (operating channel of TX PHY index 1)
+            auto txPpduPhy = m_txPhys.at(1);
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_rxPhys.at(0),
+                                txPpduPhy->GetPhyBand(),
+                                txPpduPhy->GetChannelNumber(),
+                                txPpduPhy->GetChannelWidth(),
+                                0);
+
+            // start transmission on 5 GHz low band
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                20,
+                                500);
+
+            // switch channel back to previous channel before preamble detection is finished:
+            // this is needed to verify interference helper rxing state is properly reset
+            // since ongoing reception is aborted when switching operating channel
+            Simulator::Schedule(delay + MicroSeconds(2),
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_rxPhys.at(0),
+                                m_txPhys.at(0)->GetPhyBand(),
+                                m_txPhys.at(0)->GetChannelNumber(),
+                                m_txPhys.at(0)->GetChannelWidth(),
+                                0);
+
+            delay += Seconds(1);
+            // we need 2 TX PHYs on the 5 GHz low band to have simultaneous transmissions
+            // switch operating channel of TX PHY index 2 to the 5 GHz low band
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_txPhys.at(2),
+                                txPpduPhy->GetPhyBand(),
+                                txPpduPhy->GetChannelNumber(),
+                                txPpduPhy->GetChannelWidth(),
+                                std::nullopt);
+
+            // first transmission on 5 GHz low band with high power
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                20,
+                                1000);
+
+            // second transmission on 5 GHz low band  with high power a bit later:
+            // first powers get updated updated in the corresponding bands
+            txPpduPhy = m_txPhys.at(2);
+            Simulator::Schedule(delay + NanoSeconds(10),
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                20,
+                                1000);
+
+            // restore channel for TX PHY index 2
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_txPhys.at(2),
+                                m_rxPhys.at(2)->GetPhyBand(),
+                                m_rxPhys.at(2)->GetChannelNumber(),
+                                m_rxPhys.at(2)->GetChannelWidth(),
+                                std::nullopt);
+
+            // switch channel of PHY index 0 to 5 GHz low band again
+            delay += Seconds(1);
+            txPpduPhy = m_txPhys.at(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SwitchChannel,
+                                this,
+                                m_rxPhys.at(0),
+                                txPpduPhy->GetPhyBand(),
+                                txPpduPhy->GetChannelNumber(),
+                                txPpduPhy->GetChannelWidth(),
+                                0);
+
+            // transmit PPDU on 5 GHz low band (no interference)
+            delay += Seconds(1);
+            Simulator::Schedule(delay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::SendPpdu,
+                                this,
+                                txPpduPhy,
+                                0,
+                                1500);
+
+            // check results
+            Simulator::Schedule(delay + checkResultsDelay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::CheckResults,
+                                this,
+                                0,
+                                1, // 1 RX event
+                                1, // last transmitted packet should have been successfully received
+                                1500, // 1500 bytes (payload of last transmitted packet)
+                                txPpduPhy->GetCurrentFrequencyRange(),
+                                expectedConnectedPhysPerChannel);
+
+            // reset
+            Simulator::Schedule(delay + flushResultsDelay,
+                                &SpectrumWifiPhyMultipleInterfacesTest::Reset,
+                                this);
+        }
+    }
+
+    delay += Seconds(1);
+    Simulator::Stop(delay);
     Simulator::Run();
 }
 
@@ -1603,14 +2009,24 @@
 };
 
 SpectrumWifiPhyTestSuite::SpectrumWifiPhyTestSuite()
-    : TestSuite("wifi-spectrum-wifi-phy", UNIT)
+    : TestSuite("wifi-spectrum-wifi-phy", Type::UNIT)
 {
-    AddTestCase(new SpectrumWifiPhyBasicTest, TestCase::QUICK);
-    AddTestCase(new SpectrumWifiPhyListenerTest, TestCase::QUICK);
-    AddTestCase(new SpectrumWifiPhyFilterTest, TestCase::QUICK);
-    AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(false), TestCase::QUICK);
-    AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(true), TestCase::QUICK);
-    AddTestCase(new SpectrumWifiPhyInterfacesHelperTest, TestCase::QUICK);
+    AddTestCase(new SpectrumWifiPhyBasicTest, TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumWifiPhyListenerTest, TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumWifiPhyFilterTest, TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(
+                    false,
+                    SpectrumWifiPhyMultipleInterfacesTest::ChannelSwitchScenario::BEFORE_TX),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(
+                    true,
+                    SpectrumWifiPhyMultipleInterfacesTest::ChannelSwitchScenario::BEFORE_TX),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumWifiPhyMultipleInterfacesTest(
+                    true,
+                    SpectrumWifiPhyMultipleInterfacesTest::ChannelSwitchScenario::BETWEEN_TX_RX),
+                TestCase::Duration::QUICK);
+    AddTestCase(new SpectrumWifiPhyInterfacesHelperTest, TestCase::Duration::QUICK);
 }
 
 static SpectrumWifiPhyTestSuite spectrumWifiPhyTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/tx-duration-test.cc ns-3.42/src/wifi/test/tx-duration-test.cc
--- ns-3.41/src/wifi/test/tx-duration-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/tx-duration-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -1801,11 +1801,11 @@
 };
 
 TxDurationTestSuite::TxDurationTestSuite()
-    : TestSuite("wifi-devices-tx-duration", UNIT)
+    : TestSuite("wifi-devices-tx-duration", Type::UNIT)
 {
-    AddTestCase(new TxDurationTest, TestCase::QUICK);
+    AddTestCase(new TxDurationTest, TestCase::Duration::QUICK);
 
-    AddTestCase(new PhyHeaderSectionsTest, TestCase::QUICK);
+    AddTestCase(new PhyHeaderSectionsTest, TestCase::Duration::QUICK);
 
     // 20 MHz band, HeSigBDurationTest::OFDMA, even number of users per HE-SIG-B content channel
     AddTestCase(new HeSigBDurationTest(
@@ -1816,7 +1816,7 @@
                     {96},
                     std::make_pair(2, 0), // both users in HE-SIG-B content channel 1
                     MicroSeconds(4)),     // one OFDM symbol;
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 40 MHz band, HeSigBDurationTest::OFDMA, even number of users per HE-SIG-B content channel
     AddTestCase(
@@ -1833,7 +1833,7 @@
                                std::make_pair(2, 4), // two users in HE-SIG-B content channel 1 and
                                                      // four users in HE-SIG-B content channel 2
                                MicroSeconds(4)),     // one OFDM symbol;
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 40 MHz band, HeSigBDurationTest::OFDMA, odd number of users per HE-SIG-B content channel
     AddTestCase(
@@ -1851,7 +1851,7 @@
                                std::make_pair(2, 5), // two users in HE-SIG-B content channel 1 and
                                                      // five users in HE-SIG-B content channel 2
                                MicroSeconds(8)),     // two OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 80 MHz band, OFDMA
     AddTestCase(
@@ -1871,7 +1871,7 @@
                                std::make_pair(3, 6), // three users in HE-SIG-B content channel 1
                                                      // and six users in HE-SIG-B content channel 2
                                MicroSeconds(16)),    // four OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 160 MHz band, OFDMA
     AddTestCase(
@@ -1892,7 +1892,7 @@
                                std::make_pair(4, 7), // four users in HE-SIG-B content channel 1 and
                                                      // seven users in HE-SIG-B content channel 2
                                MicroSeconds(20)),    // five OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 20 MHz band, HeSigBDurationTest::OFDMA, one unallocated RU at the middle
     AddTestCase(
@@ -1910,7 +1910,7 @@
                                {0},
                                std::make_pair(9, 0), // 9 users in HE-SIG-B content channel 1
                                MicroSeconds(8)),     // two OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 40 MHz band, HeSigBDurationTest::OFDMA, unallocated RUs at the begin and at the end of the
     // first 20 MHz subband and in the middle of the second 20 MHz subband
@@ -1925,7 +1925,7 @@
                                {112, 112},
                                std::make_pair(4, 4), // 4 users in both HE-SIG-B content channels
                                MicroSeconds(4)),     // two OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 40 MHz band, HeSigBDurationTest::OFDMA, one unallocated RUs in the first 20 MHz subband and
     // two unallocated RUs in second 20 MHz subband
@@ -1941,7 +1941,7 @@
                                {112, 112},
                                std::make_pair(4, 4), // 4 users in both HE-SIG-B content channels
                                MicroSeconds(4)),     // two OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 20 MHz band, MU-MIMO, 2 users
     AddTestCase(new HeSigBDurationTest(
@@ -1952,7 +1952,7 @@
                     {192},
                     std::make_pair(2, 0), // both users in HE-SIG-B content channel 1
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 20 MHz band, MU-MIMO, 3 users
     AddTestCase(
@@ -1965,7 +1965,7 @@
                                {192},
                                std::make_pair(3, 0), // all users in HE-SIG-B content channel 1
                                MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 20 MHz band, MU-MIMO, 4 users
     AddTestCase(
@@ -1979,7 +1979,7 @@
                                {192},
                                std::make_pair(4, 0), // all users in HE-SIG-B content channel 1
                                MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 20 MHz band, MU-MIMO, 6 users
     AddTestCase(
@@ -1995,7 +1995,7 @@
                                {192},
                                std::make_pair(6, 0), // all users in HE-SIG-B content channel 1
                                MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 20 MHz band, MU-MIMO, 8 users
     AddTestCase(
@@ -2013,7 +2013,7 @@
                                {192},
                                std::make_pair(8, 0), // all users in HE-SIG-B content channel 1
                                MicroSeconds(8)),     // two OFDM symbols
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 40 MHz band, MU-MIMO, 2 users
     AddTestCase(new HeSigBDurationTest(
@@ -2024,7 +2024,7 @@
                     {200, 200},
                     std::make_pair(1, 1), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 40 MHz band, MU-MIMO, 3 users
     AddTestCase(
@@ -2038,7 +2038,7 @@
             {200, 200},
             std::make_pair(2, 1), // 2 users in content channel 1 and 1 user in content channel 2
             MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 40 MHz band, MU-MIMO, 4 users
     AddTestCase(new HeSigBDurationTest(
@@ -2052,7 +2052,7 @@
                     {200, 200},
                     std::make_pair(2, 2), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 40 MHz band, MU-MIMO, 6 users
     AddTestCase(new HeSigBDurationTest(
@@ -2068,7 +2068,7 @@
                     {200, 200},
                     std::make_pair(3, 3), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 40 MHz band, MU-MIMO, 8 users
     AddTestCase(new HeSigBDurationTest(
@@ -2086,7 +2086,7 @@
                     {200, 200},
                     std::make_pair(4, 4), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 80 MHz band, MU-MIMO, 2 users
     AddTestCase(new HeSigBDurationTest(
@@ -2097,7 +2097,7 @@
                     {208, 208, 208, 208},
                     std::make_pair(1, 1), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 80 MHz band, MU-MIMO, 3 users
     AddTestCase(
@@ -2111,7 +2111,7 @@
             {208, 208, 208, 208},
             std::make_pair(2, 1), // 2 users in content channel 1 and 1 user in content channel 2
             MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 80 MHz band, MU-MIMO, 4 users
     AddTestCase(new HeSigBDurationTest(
@@ -2125,7 +2125,7 @@
                     {208, 208, 208, 208},
                     std::make_pair(2, 2), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 80 MHz band, MU-MIMO, 6 users
     AddTestCase(new HeSigBDurationTest(
@@ -2141,7 +2141,7 @@
                     {208, 208, 208, 208},
                     std::make_pair(3, 3), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 80 MHz band, MU-MIMO, 8 users
     AddTestCase(new HeSigBDurationTest(
@@ -2159,7 +2159,7 @@
                     {208, 208, 208, 208},
                     std::make_pair(4, 4), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 160 MHz band, MU-MIMO, 2 users
     AddTestCase(
@@ -2171,7 +2171,7 @@
             {208, 208, 208, 208, 208, 208, 208, 208},
             std::make_pair(1, 1), // users equally split between the two content channels
             MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 160 MHz band, MU-MIMO, 3 users
     AddTestCase(
@@ -2185,7 +2185,7 @@
             {208, 208, 208, 208, 208, 208, 208, 208},
             std::make_pair(2, 1), // 2 users in content channel 1 and 1 user in content channel 2
             MicroSeconds(4)),     // one OFDM symbol
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // 160 MHz band, MU-MIMO, 4 users
     AddTestCase(new HeSigBDurationTest(
@@ -2199,7 +2199,7 @@
                     {208, 208, 208, 208, 208, 208, 208, 208},
                     std::make_pair(2, 2), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 160 MHz band, MU-MIMO, 6 users
     AddTestCase(new HeSigBDurationTest(
@@ -2215,7 +2215,7 @@
                     {208, 208, 208, 208, 208, 208, 208, 208},
                     std::make_pair(3, 3), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // 160 MHz band, MU-MIMO, 8 users
     AddTestCase(new HeSigBDurationTest(
@@ -2233,7 +2233,7 @@
                     {208, 208, 208, 208, 208, 208, 208, 208},
                     std::make_pair(4, 4), // users equally split between the two content channels
                     MicroSeconds(4)),     // one OFDM symbol
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 static TxDurationTestSuite g_txDurationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-aggregation-test.cc ns-3.42/src/wifi/test/wifi-aggregation-test.cc
--- ns-3.41/src/wifi/test/wifi-aggregation-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/wifi-aggregation-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -214,7 +214,17 @@
     /*
      * Create and configure mac layer.
      */
-    m_mac = CreateObjectWithAttributes<StaWifiMac>("QosSupported", BooleanValue(true));
+    m_mac = CreateObjectWithAttributes<StaWifiMac>(
+        "QosSupported",
+        BooleanValue(true),
+        "BE_Txop",
+        PointerValue(CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue("AC_BE"))),
+        "BK_Txop",
+        PointerValue(CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue("AC_BK"))),
+        "VI_Txop",
+        PointerValue(CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue("AC_VI"))),
+        "VO_Txop",
+        PointerValue(CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue("AC_VO"))));
     m_mac->SetDevice(m_device);
     m_mac->SetWifiRemoteStationManagers(m_managers);
     for (uint8_t i = 0; i < m_params.nLinks; i++)
@@ -224,19 +234,30 @@
     m_mac->SetAddress(Mac48Address("00:00:00:00:00:01"));
     m_device->SetMac(m_mac);
     m_mac->SetWifiPhys(m_phys);
-    m_mac->ConfigureStandard(m_params.standard);
+    std::vector<Ptr<ChannelAccessManager>> caManagers;
     for (uint8_t i = 0; i < m_params.nLinks; i++)
     {
-        auto fem = m_mac->GetFrameExchangeManager(i);
+        caManagers.emplace_back(CreateObject<ChannelAccessManager>());
+    }
+    m_mac->SetChannelAccessManagers(caManagers);
+    ObjectFactory femFactory;
+    femFactory.SetTypeId(GetFrameExchangeManagerTypeIdName(m_params.standard, true));
+    std::vector<Ptr<FrameExchangeManager>> feManagers;
+    for (uint8_t i = 0; i < m_params.nLinks; i++)
+    {
+        auto fem = femFactory.Create<FrameExchangeManager>();
+        feManagers.emplace_back(fem);
         auto protectionManager = CreateObject<WifiDefaultProtectionManager>();
         protectionManager->SetWifiMac(m_mac);
         fem->SetProtectionManager(protectionManager);
         auto ackManager = CreateObject<WifiDefaultAckManager>();
         ackManager->SetWifiMac(m_mac);
         fem->SetAckManager(ackManager);
-        // here we should assign link addresses in case of MLDs, but we don't actually use link
-        // addresses in this test
+        // here we should assign distinct link addresses in case of MLDs, but we don't actually use
+        // link addresses in this test
+        fem->SetAddress(m_mac->GetAddress());
     }
+    m_mac->SetFrameExchangeManagers(feManagers);
     m_mac->SetState(StaWifiMac::ASSOCIATED);
     if (m_params.nLinks > 1)
     {
@@ -1136,15 +1157,15 @@
 };
 
 WifiAggregationTestSuite::WifiAggregationTestSuite()
-    : TestSuite("wifi-aggregation", UNIT)
+    : TestSuite("wifi-aggregation", Type::UNIT)
 {
-    AddTestCase(new AmpduAggregationTest, TestCase::QUICK);
-    AddTestCase(new TwoLevelAggregationTest, TestCase::QUICK);
-    AddTestCase(new HeAggregationTest(64), TestCase::QUICK);
-    AddTestCase(new HeAggregationTest(256), TestCase::QUICK);
-    AddTestCase(new EhtAggregationTest(512), TestCase::QUICK);
-    AddTestCase(new EhtAggregationTest(1024), TestCase::QUICK);
-    AddTestCase(new PreservePacketsInAmpdus, TestCase::QUICK);
+    AddTestCase(new AmpduAggregationTest, TestCase::Duration::QUICK);
+    AddTestCase(new TwoLevelAggregationTest, TestCase::Duration::QUICK);
+    AddTestCase(new HeAggregationTest(64), TestCase::Duration::QUICK);
+    AddTestCase(new HeAggregationTest(256), TestCase::Duration::QUICK);
+    AddTestCase(new EhtAggregationTest(512), TestCase::Duration::QUICK);
+    AddTestCase(new EhtAggregationTest(1024), TestCase::Duration::QUICK);
+    AddTestCase(new PreservePacketsInAmpdus, TestCase::Duration::QUICK);
 }
 
 static WifiAggregationTestSuite g_wifiAggregationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-channel-switching-test.cc ns-3.42/src/wifi/test/wifi-channel-switching-test.cc
--- ns-3.41/src/wifi/test/wifi-channel-switching-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/wifi-channel-switching-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -315,9 +315,9 @@
 };
 
 WifiChannelSwitchingTestSuite::WifiChannelSwitchingTestSuite()
-    : TestSuite("wifi-channel-switching", UNIT)
+    : TestSuite("wifi-channel-switching", Type::UNIT)
 {
-    AddTestCase(new WifiChannelSwitchingTest, TestCase::QUICK);
+    AddTestCase(new WifiChannelSwitchingTest, TestCase::Duration::QUICK);
 }
 
 static WifiChannelSwitchingTestSuite g_issue211TestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-dynamic-bw-op-test.cc ns-3.42/src/wifi/test/wifi-dynamic-bw-op-test.cc
--- ns-3.41/src/wifi/test/wifi-dynamic-bw-op-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/wifi-dynamic-bw-op-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -430,7 +430,7 @@
 };
 
 WifiDynamicBwOpTestSuite::WifiDynamicBwOpTestSuite()
-    : TestSuite("wifi-dynamic-bw-op", UNIT)
+    : TestSuite("wifi-dynamic-bw-op", Type::UNIT)
 {
     /**
      *                    primary20
@@ -443,7 +443,7 @@
      *          └────────┘
      */
     AddTestCase(new WifiUseAvailBwTest({"{54, 40, BAND_5GHZ, 1}", "{52, 20, BAND_5GHZ, 0}"}, 20),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     /**
      *           ─── primary 40 ───
      *           primary20
@@ -457,7 +457,7 @@
      *                                      primary20
      */
     AddTestCase(new WifiUseAvailBwTest({"{58, 80, BAND_5GHZ, 0}", "{62, 40, BAND_5GHZ, 1}"}, 40),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     /**
      *                                               ─────────── primary 80 ───────────
      *                                                       primary20
@@ -471,7 +471,7 @@
      *                             primary20
      */
     AddTestCase(new WifiUseAvailBwTest({"{50, 160, BAND_5GHZ, 5}", "{42, 80, BAND_5GHZ, 2}"}, 80),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 static WifiDynamicBwOpTestSuite g_wifiDynamicBwOpTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-eht-info-elems-test.cc ns-3.42/src/wifi/test/wifi-eht-info-elems-test.cc
--- ns-3.41/src/wifi/test/wifi-eht-info-elems-test.cc	2024-02-09 14:44:08.609795000 -0800
+++ ns-3.42/src/wifi/test/wifi-eht-info-elems-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -1372,31 +1372,31 @@
 };
 
 WifiEhtInfoElemsTestSuite::WifiEhtInfoElemsTestSuite()
-    : TestSuite("wifi-eht-info-elems", UNIT)
+    : TestSuite("wifi-eht-info-elems", Type::UNIT)
 {
-    AddTestCase(new BasicMultiLinkElementTest(), TestCase::QUICK);
-    AddTestCase(new ReducedNeighborReportTest(), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 20), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(true, 20), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 80), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(true, 40), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(true, 80), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 160), TestCase::QUICK);
-    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 320), TestCase::QUICK);
+    AddTestCase(new BasicMultiLinkElementTest(), TestCase::Duration::QUICK);
+    AddTestCase(new ReducedNeighborReportTest(), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 20), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(true, 20), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 80), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(true, 40), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(true, 80), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 160), TestCase::Duration::QUICK);
+    AddTestCase(new WifiEhtCapabilitiesIeTest(false, 320), TestCase::Duration::QUICK);
     AddTestCase(
         new TidToLinkMappingElementTest(WifiDirection::DOWNLINK, std::nullopt, std::nullopt, {}),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TidToLinkMappingElementTest(WifiDirection::UPLINK,
                                                 MicroSeconds(500 * 1024),
                                                 MicroSeconds(300 * 1024),
                                                 {{3, std::set<uint8_t>{0, 4, 6}}}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TidToLinkMappingElementTest(
                     WifiDirection::BOTH_DIRECTIONS,
                     std::nullopt,
                     MicroSeconds(100 * 1024),
                     {{3, std::set<uint8_t>{0, 4, 6}}, {6, std::set<uint8_t>{3, 7, 11, 14}}}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TidToLinkMappingElementTest(WifiDirection::DOWNLINK,
                                                 MicroSeconds(100 * 1024),
                                                 std::nullopt,
@@ -1408,9 +1408,9 @@
                                                  {5, std::set<uint8_t>{14}},
                                                  {6, std::set<uint8_t>{1, 3, 6}},
                                                  {7, std::set<uint8_t>{11, 14}}}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new EhtOperationElementTest({0, 0, 0, 0, 0}, 1, 2, 3, 4, 5, 6, 7, 8, std::nullopt),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new EhtOperationElementTest({1, 0, 0, 1, 0},
                                             1,
                                             2,
@@ -1421,7 +1421,7 @@
                                             7,
                                             8,
                                             EhtOperation::EhtOpInfo{{1}, 3, 5}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new EhtOperationElementTest({1, 1, 1, 1, 2},
                                             1,
                                             2,
@@ -1432,7 +1432,7 @@
                                             7,
                                             8,
                                             EhtOperation::EhtOpInfo{{2}, 4, 6, 3000}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 static WifiEhtInfoElemsTestSuite g_wifiEhtInfoElemsTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-emlsr-test.cc ns-3.42/src/wifi/test/wifi-emlsr-test.cc
--- ns-3.41/src/wifi/test/wifi-emlsr-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-emlsr-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -197,6 +197,8 @@
     mac.SetType("ns3::StaWifiMac",
                 "Ssid",
                 SsidValue(Ssid("wrong-ssid")),
+                "MaxMissedBeacons",
+                UintegerValue(1e6), // do not deassociate
                 "ActiveProbing",
                 BooleanValue(false));
     mac.SetEmlsrManager("ns3::DefaultEmlsrManager",
@@ -379,6 +381,8 @@
         }
         // all stations associated; start traffic if needed
         StartTraffic();
+        // stop generation of beacon frames in order to avoid interference
+        m_apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
     });
 }
 
@@ -757,11 +761,12 @@
     case WIFI_MAC_MGT_ACTION: {
         auto [category, action] = WifiActionHeader::Peek(psdu->GetPayload(0));
 
-        if (nodeId == 0 && category == WifiActionHeader::PROTECTED_EHT &&
-            action.protectedEhtAction ==
-                WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION)
+        if ((category == WifiActionHeader::PROTECTED_EHT) &&
+            (action.protectedEhtAction ==
+             WifiActionHeader::PROTECTED_EHT_EML_OPERATING_MODE_NOTIFICATION))
         {
-            CheckEmlNotificationFrame(*psdu->begin(), txVector, linkId);
+            nodeId == 0 ? CheckApEmlNotificationFrame(*psdu->begin(), txVector, linkId)
+                        : CheckStaEmlNotificationFrame(*psdu->begin(), txVector, linkId);
         }
         else if (category == WifiActionHeader::BLOCK_ACK &&
                  action.blockAck == WifiActionHeader::BLOCK_ACK_ADDBA_REQUEST)
@@ -790,6 +795,12 @@
 void
 EmlsrDlTxopTest::DoSetup()
 {
+    // Channel switch delay should be less than the ICF padding duration, otherwise
+    // DL TXOPs cannot be initiated on non-primary links
+    auto delay = std::min(MicroSeconds(100),
+                          *std::min_element(m_paddingDelay.cbegin(), m_paddingDelay.cend()));
+    Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(MicroSeconds(75)));
+
     EmlsrOperationsTestBase::DoSetup();
 
     m_errorModel = CreateObject<ListErrorModel>();
@@ -1483,12 +1494,13 @@
      */
 
     // for each EMLSR client, there should be a frame exchange with ICF and no data frame
-    // (ICF protects the EML Notification response) and two frame exchanges with data frames
+    // (ICF protects the EML Notification response) if the EML Notification response is sent
+    // while EMLSR mode is still enabled and two frame exchanges with data frames
     for (std::size_t i = 0; i < m_nEmlsrStations; i++)
     {
         // the default EMLSR Manager requests to send EML Notification frames on the link where
-        // the main PHY is operating, hence this link is an EMLSR link and the EML Notification
-        // frame is protected by an ICF
+        // the main PHY is operating; if EMLSR mode is still enabled on this link when the AP MLD
+        // sends the EML Notification response, the latter is protected by an ICF
         auto exchangeIt = frameExchanges.at(i).cbegin();
 
         auto linkIdOpt = m_staMacs[i]->GetLinkForPhy(m_mainPhyId);
@@ -1496,17 +1508,16 @@
                               true,
                               "Didn't find a link on which the main PHY is operating");
 
-        NS_TEST_EXPECT_MSG_EQ(IsTrigger(exchangeIt->front()->psduMap),
-                              true,
-                              "Expected an MU-RTS TF as ICF of first frame exchange sequence");
-        NS_TEST_EXPECT_MSG_EQ(+exchangeIt->front()->linkId,
-                              +linkIdOpt.value(),
-                              "ICF was not sent on the expected link");
-        NS_TEST_EXPECT_MSG_EQ(exchangeIt->size(),
-                              1,
-                              "Expected no data frame in the first frame exchange sequence");
-
-        frameExchanges.at(i).pop_front();
+        if (IsTrigger(exchangeIt->front()->psduMap))
+        {
+            NS_TEST_EXPECT_MSG_EQ(+exchangeIt->front()->linkId,
+                                  +linkIdOpt.value(),
+                                  "ICF was not sent on the expected link");
+            NS_TEST_EXPECT_MSG_EQ(exchangeIt->size(),
+                                  1,
+                                  "Expected no data frame in the first frame exchange sequence");
+            frameExchanges.at(i).pop_front();
+        }
 
         NS_TEST_EXPECT_MSG_GT_OR_EQ(frameExchanges.at(i).size(),
                                     2,
@@ -1613,9 +1624,9 @@
 }
 
 void
-EmlsrDlTxopTest::CheckEmlNotificationFrame(Ptr<const WifiMpdu> mpdu,
-                                           const WifiTxVector& txVector,
-                                           uint8_t linkId)
+EmlsrDlTxopTest::CheckApEmlNotificationFrame(Ptr<const WifiMpdu> mpdu,
+                                             const WifiTxVector& txVector,
+                                             uint8_t linkId)
 {
     // the AP is replying to a received EMLSR Notification frame
     auto pkt = mpdu->GetPacket()->Copy();
@@ -1706,6 +1717,126 @@
 }
 
 void
+EmlsrDlTxopTest::CheckStaEmlNotificationFrame(Ptr<const WifiMpdu> mpdu,
+                                              const WifiTxVector& txVector,
+                                              uint8_t linkId)
+{
+    // an EMLSR client is sending an EMLSR Notification frame
+    auto pkt = mpdu->GetPacket()->Copy();
+    const auto& hdr = mpdu->GetHeader();
+    WifiActionHeader::Remove(pkt);
+    MgtEmlOmn frame;
+    pkt->RemoveHeader(frame);
+
+    std::optional<std::size_t> staId;
+    for (std::size_t id = 0; id < m_nEmlsrStations; id++)
+    {
+        if (m_staMacs.at(id)->GetFrameExchangeManager(linkId)->GetAddress() == hdr.GetAddr2())
+        {
+            staId = id;
+            break;
+        }
+    }
+    NS_TEST_ASSERT_MSG_EQ(staId.has_value(),
+                          true,
+                          "Not an address of an EMLSR client " << hdr.GetAddr1());
+
+    auto phy = m_staMacs.at(*staId)->GetWifiPhy(linkId);
+    auto txDuration = WifiPhy::CalculateTxDuration(mpdu->GetSize(), txVector, phy->GetPhyBand());
+    auto ackTxVector =
+        m_apMac->GetWifiRemoteStationManager(linkId)->GetAckTxVector(hdr.GetAddr2(), txVector);
+    auto ackDuration = WifiPhy::CalculateTxDuration(GetAckSize(), ackTxVector, phy->GetPhyBand());
+    auto cfEndDuration = WifiPhy::CalculateTxDuration(
+        Create<WifiPsdu>(Create<Packet>(), WifiMacHeader(WIFI_MAC_CTL_END)),
+        m_staMacs.at(*staId)->GetWifiRemoteStationManager(linkId)->GetRtsTxVector(
+            Mac48Address::GetBroadcast(),
+            txVector.GetChannelWidth()),
+        phy->GetPhyBand());
+
+    if (frame.m_emlControl.emlsrMode != 0)
+    {
+        return;
+    }
+
+    // EMLSR mode disabled
+    auto timeToCfEnd = txDuration + phy->GetSifs() + ackDuration + phy->GetSifs() + cfEndDuration;
+
+    // before the end of the CF-End frame, this link only is not blocked on both the
+    // EMLSR client and the AP MLD
+    Simulator::Schedule(timeToCfEnd - MicroSeconds(1), [=, this]() {
+        for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+        {
+            CheckBlockedLink(m_staMacs.at(*staId),
+                             m_apMac->GetAddress(),
+                             id,
+                             WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                             id != linkId && m_staMacs.at(*staId)->IsEmlsrLink(id),
+                             "Checking links on EMLSR client " + std::to_string(*staId) +
+                                 " before the end of CF-End frame");
+            CheckBlockedLink(m_apMac,
+                             m_staMacs.at(*staId)->GetAddress(),
+                             id,
+                             WifiQueueBlockedReason::USING_OTHER_EMLSR_LINK,
+                             id != linkId && m_staMacs.at(*staId)->IsEmlsrLink(id),
+                             "Checking links of EMLSR client " + std::to_string(*staId) +
+                                 " on the AP MLD before the end of CF-End frame");
+        }
+    });
+    // after the end of the CF-End frame, all links for the EMLSR client are blocked on the
+    // AP MLD
+    Simulator::Schedule(timeToCfEnd + MicroSeconds(1), [=, this]() {
+        for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+        {
+            if (m_staMacs.at(*staId)->IsEmlsrLink(id))
+            {
+                CheckBlockedLink(
+                    m_apMac,
+                    m_staMacs.at(*staId)->GetAddress(),
+                    id && m_staMacs.at(*staId)->IsEmlsrLink(id),
+                    WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                    true,
+                    "Checking links of EMLSR client " + std::to_string(*staId) +
+                        " are all blocked on the AP MLD right after the end of CF-End");
+            }
+        }
+    });
+    // before the end of the transition delay, all links for the EMLSR client are still
+    // blocked on the AP MLD
+    Simulator::Schedule(timeToCfEnd + m_transitionDelay.at(*staId) - MicroSeconds(1), [=, this]() {
+        for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+        {
+            if (m_staMacs.at(*staId)->IsEmlsrLink(id))
+            {
+                CheckBlockedLink(m_apMac,
+                                 m_staMacs.at(*staId)->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                                 true,
+                                 "Checking links of EMLSR client " + std::to_string(*staId) +
+                                     " are all blocked on the AP MLD before the end of "
+                                     "transition delay");
+            }
+        }
+    });
+    // immediately after the transition delay, all links for the EMLSR client are unblocked
+    Simulator::Schedule(timeToCfEnd + m_transitionDelay.at(*staId) + MicroSeconds(1), [=, this]() {
+        for (uint8_t id = 0; id < m_apMac->GetNLinks(); id++)
+        {
+            if (m_staMacs.at(*staId)->IsEmlsrLink(id))
+            {
+                CheckBlockedLink(m_apMac,
+                                 m_staMacs.at(*staId)->GetAddress(),
+                                 id,
+                                 WifiQueueBlockedReason::WAITING_EMLSR_TRANSITION_DELAY,
+                                 false,
+                                 "Checking links of EMLSR client " + std::to_string(*staId) +
+                                     " are all unblocked on the AP MLD after the transition delay");
+            }
+        }
+    });
+}
+
+void
 EmlsrDlTxopTest::CheckInitialControlFrame(Ptr<const WifiMpdu> mpdu,
                                           const WifiTxVector& txVector,
                                           uint8_t linkId)
@@ -2284,7 +2415,7 @@
                     "This test requires at least two links to be configured as EMLSR links");
     for (uint8_t id = 0; id < 3; id++)
     {
-        if (m_emlsrLinks.count(id) == 0)
+        if (!m_emlsrLinks.contains(id))
         {
             // non-EMLSR link found
             m_nonEmlsrLink = id;
@@ -3215,6 +3346,7 @@
     Config::SetDefault("ns3::DefaultEmlsrManager::SwitchAuxPhy", BooleanValue(m_switchAuxPhy));
     Config::SetDefault("ns3::EmlsrManager::ResetCamState", BooleanValue(m_resetCamState));
     Config::SetDefault("ns3::EmlsrManager::AuxPhyChannelWidth", UintegerValue(m_auxPhyMaxChWidth));
+    Config::SetDefault("ns3::WifiPhy::ChannelSwitchDelay", TimeValue(MicroSeconds(75)));
 
     EmlsrOperationsTestBase::DoSetup();
 
@@ -3458,7 +3590,7 @@
     const std::size_t nRxOk = 4; // successfully received ICFs
 
     NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(),
-                                m_txPsdusPos + 3 + nRxOk * 4,
+                                m_txPsdusPos + 2 + nRxOk * 4,
                                 "Insufficient number of TX PSDUs");
 
     // m_txPsdusPos points to ADDBA_RESPONSE, then ACK and then ICF
@@ -3490,41 +3622,42 @@
 }
 
 WifiEmlsrTestSuite::WifiEmlsrTestSuite()
-    : TestSuite("wifi-emlsr", UNIT)
+    : TestSuite("wifi-emlsr", Type::UNIT)
 {
-    AddTestCase(new EmlOperatingModeNotificationTest(), TestCase::QUICK);
-    AddTestCase(new EmlOmnExchangeTest({1, 2}, MicroSeconds(0)), TestCase::QUICK);
-    AddTestCase(new EmlOmnExchangeTest({1, 2}, MicroSeconds(2048)), TestCase::QUICK);
-    AddTestCase(new EmlOmnExchangeTest({0, 1, 2, 3}, MicroSeconds(0)), TestCase::QUICK);
-    AddTestCase(new EmlOmnExchangeTest({0, 1, 2, 3}, MicroSeconds(2048)), TestCase::QUICK);
+    AddTestCase(new EmlOperatingModeNotificationTest(), TestCase::Duration::QUICK);
+    AddTestCase(new EmlOmnExchangeTest({1, 2}, MicroSeconds(0)), TestCase::Duration::QUICK);
+    AddTestCase(new EmlOmnExchangeTest({1, 2}, MicroSeconds(2048)), TestCase::Duration::QUICK);
+    AddTestCase(new EmlOmnExchangeTest({0, 1, 2, 3}, MicroSeconds(0)), TestCase::Duration::QUICK);
+    AddTestCase(new EmlOmnExchangeTest({0, 1, 2, 3}, MicroSeconds(2048)),
+                TestCase::Duration::QUICK);
     for (const auto& emlsrLinks :
          {std::set<uint8_t>{0, 1, 2}, std::set<uint8_t>{1, 2}, std::set<uint8_t>{0, 1}})
     {
         AddTestCase(
             new EmlsrDlTxopTest(
                 {1, 0, emlsrLinks, {MicroSeconds(32)}, {MicroSeconds(32)}, MicroSeconds(512)}),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(
             new EmlsrDlTxopTest(
                 {1, 1, emlsrLinks, {MicroSeconds(64)}, {MicroSeconds(64)}, MicroSeconds(512)}),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
         AddTestCase(new EmlsrDlTxopTest({2,
                                          2,
                                          emlsrLinks,
                                          {MicroSeconds(128), MicroSeconds(256)},
                                          {MicroSeconds(128), MicroSeconds(256)},
                                          MicroSeconds(512)}),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
     }
 
     for (auto genBackoffIfTxopWithoutTx : {true, false})
     {
         AddTestCase(new EmlsrUlTxopTest(
                         {{0, 1, 2}, 40, 20, MicroSeconds(5504), 3, genBackoffIfTxopWithoutTx}),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(
             new EmlsrUlTxopTest({{0, 1}, 40, 20, MicroSeconds(5504), 1, genBackoffIfTxopWithoutTx}),
-            TestCase::QUICK);
+            TestCase::Duration::QUICK);
     }
 
     for (bool switchAuxPhy : {true, false})
@@ -3535,7 +3668,7 @@
             {
                 AddTestCase(
                     new EmlsrLinkSwitchTest({switchAuxPhy, resetCamState, auxPhyMaxChWidth}),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
             }
         }
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-emlsr-test.h ns-3.42/src/wifi/test/wifi-emlsr-test.h
--- ns-3.41/src/wifi/test/wifi-emlsr-test.h	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-emlsr-test.h	2024-05-29 15:29:47.216073800 -0700
@@ -397,16 +397,28 @@
     void CheckPmModeAfterAssociation(const Mac48Address& address);
 
     /**
-     * Check that appropriate actions are taken by the AP MLD transmitting an EML Operating Mode
+     * Check that appropriate actions are taken when the AP MLD transmits an EML Operating Mode
      * Notification response frame to an EMLSR client on the given link.
      *
      * \param mpdu the MPDU carrying the EML Operating Mode Notification frame
      * \param txVector the TXVECTOR used to send the PPDU
      * \param linkId the ID of the given link
      */
-    void CheckEmlNotificationFrame(Ptr<const WifiMpdu> mpdu,
-                                   const WifiTxVector& txVector,
-                                   uint8_t linkId);
+    void CheckApEmlNotificationFrame(Ptr<const WifiMpdu> mpdu,
+                                     const WifiTxVector& txVector,
+                                     uint8_t linkId);
+
+    /**
+     * Check that appropriate actions are taken when an EMLSR client transmits an EML Operating
+     * Mode Notification frame to the AP MLD on the given link.
+     *
+     * \param mpdu the MPDU carrying the EML Operating Mode Notification frame
+     * \param txVector the TXVECTOR used to send the PPDU
+     * \param linkId the ID of the given link
+     */
+    void CheckStaEmlNotificationFrame(Ptr<const WifiMpdu> mpdu,
+                                      const WifiTxVector& txVector,
+                                      uint8_t linkId);
 
     /**
      * Check that appropriate actions are taken by the AP MLD transmitting an initial
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-error-rate-models-test.cc ns-3.42/src/wifi/test/wifi-error-rate-models-test.cc
--- ns-3.41/src/wifi/test/wifi-error-rate-models-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-error-rate-models-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -404,7 +404,6 @@
   public:
     using InterferenceHelper::CalculatePayloadChunkSuccessRate;
     using InterferenceHelper::CalculateSnr;
-    using InterferenceHelper::InterferenceHelper;
 };
 
 /**
@@ -1052,60 +1051,60 @@
 };
 
 WifiErrorRateModelsTestSuite::WifiErrorRateModelsTestSuite()
-    : TestSuite("wifi-error-rate-models", UNIT)
+    : TestSuite("wifi-error-rate-models", Type::UNIT)
 {
-    AddTestCase(new WifiErrorRateModelsTestCaseDsss, TestCase::QUICK);
-    AddTestCase(new WifiErrorRateModelsTestCaseNist, TestCase::QUICK);
-    AddTestCase(new WifiErrorRateModelsTestCaseMimo, TestCase::QUICK);
+    AddTestCase(new WifiErrorRateModelsTestCaseDsss, TestCase::Duration::QUICK);
+    AddTestCase(new WifiErrorRateModelsTestCaseNist, TestCase::Duration::QUICK);
+    AddTestCase(new WifiErrorRateModelsTestCaseMimo, TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedHtMcs0-1458bytes",
                                                 HtPhy::GetHtMcs0(),
                                                 1458),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TableBasedErrorRateTestCase("DefaultTableBasedHtMcs0-32bytes", HtPhy::GetHtMcs0(), 32),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedHtMcs0-1000bytes",
                                                 HtPhy::GetHtMcs0(),
                                                 1000),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TableBasedErrorRateTestCase("DefaultTableBasedHtMcs0-1byte", HtPhy::GetHtMcs0(), 1),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedHtMcs0-2000bytes",
                                                 HtPhy::GetHtMcs0(),
                                                 2000),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedHtMcs7-1500bytes",
                                                 HtPhy::GetHtMcs7(),
                                                 1500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedVhtMcs0-1458bytes",
                                                 VhtPhy::GetVhtMcs0(),
                                                 1458),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedVhtMcs0-32bytes",
                                                 VhtPhy::GetVhtMcs0(),
                                                 32),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedVhtMcs0-1000bytes",
                                                 VhtPhy::GetVhtMcs0(),
                                                 1000),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(
         new TableBasedErrorRateTestCase("DefaultTableBasedVhtMcs0-1byte", VhtPhy::GetVhtMcs0(), 1),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedVhtMcs0-2000bytes",
                                                 VhtPhy::GetVhtMcs0(),
                                                 2000),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("DefaultTableBasedVhtMcs8-1500bytes",
                                                 VhtPhy::GetVhtMcs8(),
                                                 1500),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     AddTestCase(new TableBasedErrorRateTestCase("FallbackTableBasedHeMcs11-1458bytes",
                                                 HePhy::GetHeMcs11(),
                                                 1458),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 }
 
 static WifiErrorRateModelsTestSuite wifiErrorRateModelsTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-fils-frame-test.cc ns-3.42/src/wifi/test/wifi-fils-frame-test.cc
--- ns-3.41/src/wifi/test/wifi-fils-frame-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/test/wifi-fils-frame-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2024 Rami Abdallah
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ns3/ap-wifi-mac.h"
+#include "ns3/assert.h"
+#include "ns3/attribute-container.h"
+#include "ns3/boolean.h"
+#include "ns3/enum.h"
+#include "ns3/error-model.h"
+#include "ns3/log.h"
+#include "ns3/mac48-address.h"
+#include "ns3/mgt-action-headers.h"
+#include "ns3/mgt-headers.h"
+#include "ns3/mobility-helper.h"
+#include "ns3/node-container.h"
+#include "ns3/object-factory.h"
+#include "ns3/rng-seed-manager.h"
+#include "ns3/simulator.h"
+#include "ns3/spectrum-helper.h"
+#include "ns3/string.h"
+#include "ns3/test.h"
+#include "ns3/tuple.h"
+#include "ns3/wifi-mac-header.h"
+#include "ns3/wifi-mac-helper.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/wifi-psdu.h"
+#include "ns3/wifi-utils.h"
+#include "ns3/yans-wifi-helper.h"
+#include "ns3/yans-wifi-phy.h"
+
+#include <algorithm>
+#include <filesystem>
+#include <iterator>
+#include <optional>
+#include <variant>
+
+using namespace ns3;
+
+/// \ingroup wifi-test
+/// \ingroup tests
+/// \brief Fast Initial Link Setup (FILS) frame Test Suite
+/// Test suite intended to test (de)serialization and timing
+/// of frames associated with FILS procedure.
+/// The test creates a BSS consisting of an AP and client and
+/// and analyzes the timings and contents of frames associated
+/// with FILS procedure.
+
+NS_LOG_COMPONENT_DEFINE("WifiFilsFrameTestSuite");
+
+static const auto DEFAULT_BANDWIDTH = 20;
+static const auto INVALID_CHAN_NUM = 0;
+static const auto DEFAULT_PRIMARY_INDEX = 0;
+static const auto DEFAULT_SIM_STOP_TIME = MilliSeconds(610);
+static const auto DEFAULT_RNG_SEED = 3;
+static const auto DEFAULT_RNG_RUN = 7;
+static const auto DEFAULT_STREAM_INDEX = 100;
+static const auto DUMMY_AP_ADDR = Mac48Address("00:00:00:00:00:10");
+static const auto DEFAULT_STANDARD = WifiStandard::WIFI_STANDARD_80211ax;
+static const auto DEFAULT_BAND = WifiPhyBand::WIFI_PHY_BAND_6GHZ;
+static const auto DEFAULT_SSID = "01234567890123456789012345678901"; // max length (32 bytes)
+static const auto DEFAULT_BCN_INTRVL = 100 * WIFI_TU;
+static const auto DEFAULT_FILS_INTRVL = 20 * WIFI_TU;
+static const auto DEFAULT_TIMING_TOLERANCE = MicroSeconds(100);
+static const auto DEFAULT_UNSOL_PROBE_RESP_EN = false;
+static const auto DEFAULT_PCAP_PREFIX = "ap-fils";
+static const auto DEFAULT_OUTDIR = ".";
+static const auto DEFAULT_ENABLE_PCAP = false;
+static const auto DEFAULT_AP_LOC = Vector(0.01, 0, 0);
+static const auto DEFAULT_CLIENT_LOC = Vector(0, 0, 0);
+static const uint8_t WIFI_6GHZ_FD_PHY_IDX = 4;
+
+/// @brief  Wi-Fi FILS frame test parameters
+struct WifiFilsFrameTestParams
+{
+    uint16_t bw{DEFAULT_BANDWIDTH};                     ///< Operation bandwidth
+    std::string ssid{DEFAULT_SSID};                     ///< SSID name
+    uint8_t nss{0};                                     ///< Number of spatial streams
+    Time bcnIntrvl{DEFAULT_BCN_INTRVL};                 ///< Time between Beacons
+    Time filsIntrvl{DEFAULT_FILS_INTRVL};               ///< Time between FILS frames
+    bool unsolProbeRespEn{DEFAULT_UNSOL_PROBE_RESP_EN}; ///< Unsolicited Probe Response enable
+    uint8_t expNssFld{0};                               ///< Expected NSS field
+    uint8_t expChWidFld{0};                             ///< Expected Channel Width field
+};
+
+/// @ingroup wifi-test
+/// @ingroup tests
+/// Test FILS frames
+class WifiFilsFrameTest : public TestCase
+{
+  public:
+    /// @brief  constructor
+    /// @param params the parameters for this test
+    WifiFilsFrameTest(const WifiFilsFrameTestParams& params);
+
+    /// Transmitted PSDUs
+    struct PsduCapture
+    {
+        Time timeSt;              ///< timestamp
+        Ptr<const WifiPsdu> psdu; ///< PSDU
+    };
+
+  private:
+    /// Timing statistic for test validation
+    struct TimeStats
+    {
+        size_t cntBcns{0};                  ///< Beacon frames count
+        Time bcnTimeSt{0};                  ///< last Beacon timestamp
+        size_t cntFilsOrUnsolProbeResps{0}; ///< FILS Discovery or Unsolicited Probe Response count
+        Time filsOrUnsolProbeRespTimeSt{0}; ///< last FILS Discovery or Unsolicited Probe Response
+                                            ///< timestamp
+        Time filsOrUnsolProbeRespTimeDelta{0}; ///< time between last FILS Discovery or Unsolicited
+                                               ///< Probe Response and last Beacon
+    };
+
+    /// @brief setup a WifiNetDevice
+    /// @param channel the channel to attach to
+    /// @param isAp whether the device is an AP
+    /// @return the created WifiNetDevice
+    Ptr<WifiNetDevice> SetupDevice(Ptr<YansWifiChannel>& channel, bool isAp);
+
+    /// @brief callback connected to PSDU TX begin trace source
+    /// @param psduMap the transmitted PSDU map
+    /// @param txVector the TXVECTOR
+    /// @param txPowerW the TX power in Watts
+    void PsduTxCallback(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
+
+    /// @brief validate the given FILS Discovery frame
+    /// @param filsDisc the FILS Discovery frame
+    void ValidateFilsDiscFrame(const FilsDiscHeader& filsDisc);
+
+    /// @brief check the correctness of the test
+    void ValidateTest();
+
+    /// @brief Check the number of FILS Discovery frames or unsolicited Probe Response frames
+    ///        transmitted since the last Beacon frame
+    /// @param psduCapt information about the transmitted Beacon frame
+    void ValidateCnt(const PsduCapture& psduCapt);
+
+    /// @brief check the timing of the transmitted FILS Discovery or unsolicited Probe Response
+    /// @param psduCapt information about the FILS Discovery or unsolicited Probe Response
+    void ValidateTiming(const PsduCapture& psduCapt);
+
+    /// @brief Get the FILS Discovery header, if present in the given frame
+    /// @param psduCapt information about the given frame
+    /// @return the FILS Discovery header, if present
+    std::optional<FilsDiscHeader> GetFilsDiscFrame(const PsduCapture& psduCapt);
+
+    void DoSetup() override;
+    void DoTeardown() override;
+    void DoRun() override;
+
+    TimeStats m_timeStats;                ///< collected timing statistic
+    Ptr<WifiNetDevice> m_ap{nullptr};     ///< AP device
+    Ptr<WifiNetDevice> m_client{nullptr}; ///< Client device
+    WifiFilsFrameTestParams m_params;     ///< Test parameters
+    std::vector<PsduCapture> m_txPsdus{}; ///< TX PSDUS frame infos
+};
+
+WifiFilsFrameTest::WifiFilsFrameTest(const WifiFilsFrameTestParams& params)
+    : TestCase("WifiFilsFrameTest"),
+      m_params(params)
+{
+}
+
+Ptr<WifiNetDevice>
+WifiFilsFrameTest::SetupDevice(Ptr<YansWifiChannel>& channel, bool isAp)
+{
+    NodeContainer node;
+    YansWifiPhyHelper phy;
+    WifiMacHelper mac;
+    WifiHelper wifi;
+    MobilityHelper mobility;
+    node.Create(1);
+    phy.SetChannel(channel);
+    TupleValue<UintegerValue, UintegerValue, EnumValue<WifiPhyBand>, UintegerValue> channelValue;
+    channelValue.Set(
+        WifiPhy::ChannelTuple{INVALID_CHAN_NUM, m_params.bw, DEFAULT_BAND, DEFAULT_PRIMARY_INDEX});
+    phy.Set("ChannelSettings", channelValue);
+    phy.Set("Antennas", UintegerValue(m_params.nss));
+    phy.Set("MaxSupportedTxSpatialStreams", UintegerValue(m_params.nss));
+    phy.Set("MaxSupportedRxSpatialStreams", UintegerValue(m_params.nss));
+
+    wifi.SetStandard(DEFAULT_STANDARD);
+    wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager");
+
+    if (isAp)
+    {
+        mac.SetType("ns3::ApWifiMac",
+                    "Ssid",
+                    SsidValue(Ssid(m_params.ssid)),
+                    "BeaconGeneration",
+                    BooleanValue(true),
+                    "BeaconInterval",
+                    TimeValue(m_params.bcnIntrvl),
+                    "FdBeaconInterval6GHz",
+                    TimeValue(m_params.filsIntrvl),
+                    "SendUnsolProbeResp",
+                    BooleanValue(m_params.unsolProbeRespEn));
+    }
+    else
+    {
+        mac.SetType("ns3::StaWifiMac",
+                    "Ssid",
+                    SsidValue(Ssid(m_params.ssid)),
+                    "ActiveProbing",
+                    BooleanValue(false));
+    }
+    auto testDevs = wifi.Install(phy, mac, node);
+    wifi.AssignStreams(testDevs, DEFAULT_STREAM_INDEX);
+    auto dev = DynamicCast<WifiNetDevice>(testDevs.Get(0));
+    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+    mobility.Install(node);
+    node.Get(0)->GetObject<MobilityModel>()->SetPosition(isAp ? DEFAULT_AP_LOC
+                                                              : DEFAULT_CLIENT_LOC);
+    phy.SetPcapDataLinkType(WifiPhyHelper::DLT_IEEE802_11_RADIO);
+    if (isAp && DEFAULT_ENABLE_PCAP)
+    {
+        auto path = std::filesystem::path(DEFAULT_OUTDIR);
+        phy.EnablePcap(path.append(DEFAULT_PCAP_PREFIX).string(), testDevs);
+    }
+    return dev;
+}
+
+void
+WifiFilsFrameTest::PsduTxCallback(WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
+{
+    auto psdu = psduMap[SU_STA_ID];
+    m_txPsdus.push_back({Simulator::Now(), psdu});
+    NS_LOG_DEBUG("MPDU " << **psdu->begin());
+}
+
+void
+WifiFilsFrameTest::DoSetup()
+{
+    RngSeedManager::SetSeed(DEFAULT_RNG_SEED);
+    RngSeedManager::SetRun(DEFAULT_RNG_RUN);
+    auto channel = YansWifiChannelHelper::Default().Create();
+    // setup devices and capabilities
+    m_ap = SetupDevice(channel, true);
+    m_client = SetupDevice(channel, false);
+    // setup AP TX PSDU trace
+    auto phy = m_ap->GetPhy();
+    phy->TraceConnectWithoutContext("PhyTxPsduBegin",
+                                    MakeCallback(&WifiFilsFrameTest::PsduTxCallback, this));
+}
+
+void
+WifiFilsFrameTest::ValidateCnt(const PsduCapture& psduCapt)
+{
+    if (m_timeStats.cntBcns > 0)
+    {
+        NS_TEST_ASSERT_MSG_EQ(
+            m_timeStats.cntFilsOrUnsolProbeResps,
+            static_cast<std::size_t>((m_params.bcnIntrvl / m_params.filsIntrvl).GetHigh() - 1),
+            "Number of FILS or Unsolicited Response Frames per Beacon Interval is not expected");
+    }
+    m_timeStats.bcnTimeSt = psduCapt.timeSt;
+    m_timeStats.cntBcns++;
+    m_timeStats.cntFilsOrUnsolProbeResps = 0;
+}
+
+void
+WifiFilsFrameTest::ValidateTiming(const PsduCapture& psduCapt)
+{
+    m_timeStats.filsOrUnsolProbeRespTimeDelta =
+        psduCapt.timeSt - (m_timeStats.cntFilsOrUnsolProbeResps > 0
+                               ? m_timeStats.filsOrUnsolProbeRespTimeSt
+                               : m_timeStats.bcnTimeSt);
+    m_timeStats.filsOrUnsolProbeRespTimeSt = psduCapt.timeSt;
+    m_timeStats.cntFilsOrUnsolProbeResps++;
+    NS_TEST_ASSERT_MSG_EQ_TOL(
+        m_timeStats.filsOrUnsolProbeRespTimeDelta,
+        m_params.filsIntrvl,
+        DEFAULT_TIMING_TOLERANCE,
+        "Timing of FILS or Unsolicited Response frames is not as expected at time "
+            << psduCapt.timeSt.GetTimeStep());
+}
+
+std::optional<FilsDiscHeader>
+WifiFilsFrameTest::GetFilsDiscFrame(const PsduCapture& psduCapt)
+{
+    auto pkt = psduCapt.psdu->GetPayload(0)->Copy();
+    WifiActionHeader actionHdr;
+    pkt->RemoveHeader(actionHdr);
+    if ((actionHdr.GetCategory() == WifiActionHeader::PUBLIC) &&
+        (actionHdr.GetAction().publicAction == WifiActionHeader::FILS_DISCOVERY))
+    {
+        FilsDiscHeader filsDisc;
+        pkt->PeekHeader(filsDisc);
+        return filsDisc;
+    }
+    return std::nullopt;
+}
+
+void
+WifiFilsFrameTest::ValidateTest()
+{
+    for (const auto& psduCapt : m_txPsdus)
+    {
+        auto hdr = psduCapt.psdu->GetHeader(0);
+        if (hdr.IsBeacon())
+        {
+            ValidateCnt(psduCapt);
+        }
+        else
+        {
+            if (m_params.unsolProbeRespEn && hdr.IsProbeResp() && hdr.GetAddr1().IsBroadcast())
+            { // Unsolicited Probe Response frame
+                ValidateTiming(psduCapt);
+            }
+            else if (hdr.IsAction())
+            { // possible FILS Discovery frame
+                if (auto filsDisc = GetFilsDiscFrame(psduCapt))
+                {
+                    ValidateFilsDiscFrame(filsDisc.value());
+                    ValidateTiming(psduCapt);
+                }
+            }
+        }
+        if (m_timeStats.cntBcns == DEFAULT_SIM_STOP_TIME / m_params.bcnIntrvl)
+        {
+            break;
+        }
+    }
+}
+
+void
+WifiFilsFrameTest::ValidateFilsDiscFrame(const FilsDiscHeader& filsDisc)
+{
+    NS_TEST_ASSERT_MSG_EQ(filsDisc.GetSsid(), m_params.ssid, "FILS Discovery frame SSID mismatch");
+    NS_TEST_ASSERT_MSG_EQ(+filsDisc.m_fdCap->m_chWidth,
+                          +m_params.expChWidFld,
+                          "FILS Discovery frame channel width mismatch");
+    NS_TEST_ASSERT_MSG_EQ(+filsDisc.m_fdCap->m_maxNss,
+                          +m_params.expNssFld,
+                          "FILS Discovery frame NSS mismatch");
+    NS_TEST_ASSERT_MSG_EQ(+filsDisc.m_fdCap->m_phyIdx,
+                          +WIFI_6GHZ_FD_PHY_IDX,
+                          "FILS Discovery frame PHY idx mismatch");
+}
+
+void
+WifiFilsFrameTest::DoRun()
+{
+    Simulator::Stop(DEFAULT_SIM_STOP_TIME);
+    Simulator::Run();
+    Simulator::Destroy();
+    ValidateTest();
+}
+
+void
+WifiFilsFrameTest::DoTeardown()
+{
+    m_ap->Dispose();
+    m_ap = nullptr;
+    m_client->Dispose();
+    m_client = nullptr;
+    m_txPsdus.clear();
+}
+
+/// Testcases for FILS frame test
+enum class WifiFilsFrameTestCase : uint8_t
+{
+    BW20MHZ_NSS1_DISC = 0,
+    BW20MHZ_NSS3_DISC,
+    BW40MHZ_NSS2_DISC,
+    BW80MHZ_NSS2_DISC,
+    BW160MHZ_NSS2_DISC,
+    BW160MHZ_NSS2_PROBE,
+    COUNT,
+};
+
+WifiFilsFrameTestParams
+WifiFilsFrameTestBuildCase(const WifiFilsFrameTestCase& tc)
+{
+    WifiFilsFrameTestParams params{};
+    switch (tc)
+    {
+    case WifiFilsFrameTestCase::BW20MHZ_NSS1_DISC:
+        params.bw = 20;
+        params.ssid = DEFAULT_SSID;
+        params.nss = 1;
+        params.expChWidFld = 0;
+        params.expNssFld = 0;
+        break;
+    case WifiFilsFrameTestCase::BW20MHZ_NSS3_DISC:
+        params.bw = 20;
+        params.ssid = "BW20MHZ_NSS3";
+        params.nss = 3;
+        params.filsIntrvl = 15 * WIFI_TU;
+        params.expChWidFld = 0;
+        params.expNssFld = 2;
+        break;
+    case WifiFilsFrameTestCase::BW40MHZ_NSS2_DISC:
+        params.bw = 40;
+        params.ssid = "BW40MHZ_NSS2";
+        params.nss = 2;
+        params.filsIntrvl = 10 * WIFI_TU;
+        params.expChWidFld = 1;
+        params.expNssFld = 1;
+        break;
+    case WifiFilsFrameTestCase::BW80MHZ_NSS2_DISC:
+        params.bw = 80;
+        params.ssid = "BW80MHZ_NSS2";
+        params.nss = 2;
+        params.filsIntrvl = 7 * WIFI_TU;
+        params.expChWidFld = 2;
+        params.expNssFld = 1;
+        break;
+    case WifiFilsFrameTestCase::BW160MHZ_NSS2_DISC:
+        params.bw = 160;
+        params.ssid = "BW160MHZ_NSS2";
+        params.nss = 2;
+        params.filsIntrvl = 5 * WIFI_TU;
+        params.expChWidFld = 3;
+        params.expNssFld = 1;
+        break;
+    case WifiFilsFrameTestCase::BW160MHZ_NSS2_PROBE:
+        params.bw = 160;
+        params.ssid = "BW160MHZ_NSS2";
+        params.nss = 2;
+        params.unsolProbeRespEn = true;
+        params.expChWidFld = 3;
+        params.expNssFld = 1;
+        break;
+    default:
+        NS_ABORT_MSG("Testcase is unsupported");
+        break;
+    }
+    return params;
+}
+
+/// \ingroup wifi-test
+/// \ingroup tests
+/// \brief WiFi FILS frame Test Suite
+class WifiFilsFrameTestSuite : public TestSuite
+{
+  public:
+    WifiFilsFrameTestSuite();
+};
+
+WifiFilsFrameTestSuite::WifiFilsFrameTestSuite()
+    : TestSuite("wifi-fils-frame", Type::UNIT)
+{
+    std::vector<WifiFilsFrameTestParams> testCases{
+        {WifiFilsFrameTestBuildCase(WifiFilsFrameTestCase::BW20MHZ_NSS1_DISC)},
+        {WifiFilsFrameTestBuildCase(WifiFilsFrameTestCase::BW20MHZ_NSS3_DISC)},
+        {WifiFilsFrameTestBuildCase(WifiFilsFrameTestCase::BW40MHZ_NSS2_DISC)},
+        {WifiFilsFrameTestBuildCase(WifiFilsFrameTestCase::BW80MHZ_NSS2_DISC)},
+        {WifiFilsFrameTestBuildCase(WifiFilsFrameTestCase::BW160MHZ_NSS2_DISC)},
+        {WifiFilsFrameTestBuildCase(WifiFilsFrameTestCase::BW160MHZ_NSS2_PROBE)},
+    };
+    for (const auto& tc : testCases)
+    {
+        AddTestCase(new WifiFilsFrameTest(tc), TestCase::Duration::QUICK);
+    }
+}
+
+static WifiFilsFrameTestSuite g_WifiFilsFrameTestSuite; /// the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-he-info-elems-test.cc ns-3.42/src/wifi/test/wifi-he-info-elems-test.cc
--- ns-3.41/src/wifi/test/wifi-he-info-elems-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/test/wifi-he-info-elems-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2024 Universita' degli Studi di Napoli Federico II
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Stefano Avallone <stavallo@unina.it>
+ */
+
+#include "ns3/he-6ghz-band-capabilities.h"
+#include "ns3/he-operation.h"
+#include "ns3/header-serialization-test.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("WifiHeInfoElemsTest");
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief Test HE Operation information element serialization and deserialization
+ */
+class HeOperationElementTest : public HeaderSerializationTestCase
+{
+  public:
+    HeOperationElementTest();
+
+  private:
+    void DoRun() override;
+};
+
+HeOperationElementTest::HeOperationElementTest()
+    : HeaderSerializationTestCase(
+          "Check serialization and deserialization of HE Operation elements")
+{
+}
+
+void
+HeOperationElementTest::DoRun()
+{
+    HeOperation heOperation;
+
+    heOperation.m_heOpParams.m_defaultPeDuration = 6;
+    heOperation.m_heOpParams.m_twtRequired = 1;
+    heOperation.m_heOpParams.m_txopDurRtsThresh = 1000;
+    heOperation.m_heOpParams.m_erSuDisable = 1;
+
+    heOperation.m_bssColorInfo.m_bssColor = 44;
+    heOperation.m_bssColorInfo.m_bssColorDisabled = 1;
+
+    heOperation.SetMaxHeMcsPerNss(8, 7);
+    heOperation.SetMaxHeMcsPerNss(6, 8);
+    heOperation.SetMaxHeMcsPerNss(4, 9);
+    heOperation.SetMaxHeMcsPerNss(2, 10);
+    heOperation.SetMaxHeMcsPerNss(1, 11);
+
+    TestHeaderSerialization(heOperation);
+
+    heOperation.m_6GHzOpInfo = HeOperation::OpInfo6GHz{};
+    heOperation.m_6GHzOpInfo->m_primCh = 191;
+    heOperation.m_6GHzOpInfo->m_chWid = 2;
+    heOperation.m_6GHzOpInfo->m_dupBeacon = 1;
+    heOperation.m_6GHzOpInfo->m_regInfo = 6;
+    heOperation.m_6GHzOpInfo->m_chCntrFreqSeg0 = 157;
+    heOperation.m_6GHzOpInfo->m_chCntrFreqSeg1 = 201;
+    heOperation.m_6GHzOpInfo->m_minRate = 211;
+
+    TestHeaderSerialization(heOperation);
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief Test HE 6 GHz Band Capabilities information element serialization and deserialization
+ */
+class He6GhzBandCapabilitiesTest : public HeaderSerializationTestCase
+{
+  public:
+    He6GhzBandCapabilitiesTest();
+
+  private:
+    void DoRun() override;
+};
+
+He6GhzBandCapabilitiesTest::He6GhzBandCapabilitiesTest()
+    : HeaderSerializationTestCase(
+          "Check serialization and deserialization of HE 6 GHz Band Capabilities elements")
+{
+}
+
+void
+He6GhzBandCapabilitiesTest::DoRun()
+{
+    He6GhzBandCapabilities he6GhzBandCapabilities;
+
+    he6GhzBandCapabilities.m_capabilitiesInfo.m_minMpduStartSpacing = 5;
+    he6GhzBandCapabilities.SetMaxAmpduLength((static_cast<uint32_t>(1) << 18) - 1);
+    he6GhzBandCapabilities.SetMaxMpduLength(11454);
+    he6GhzBandCapabilities.m_capabilitiesInfo.m_smPowerSave = 3;
+    he6GhzBandCapabilities.m_capabilitiesInfo.m_rdResponder = 1;
+    he6GhzBandCapabilities.m_capabilitiesInfo.m_rxAntennaPatternConsistency = 1;
+    he6GhzBandCapabilities.m_capabilitiesInfo.m_txAntennaPatternConsistency = 1;
+
+    TestHeaderSerialization(he6GhzBandCapabilities);
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief wifi HE Information Elements Test Suite
+ */
+class WifiHeInfoElemsTestSuite : public TestSuite
+{
+  public:
+    WifiHeInfoElemsTestSuite();
+};
+
+WifiHeInfoElemsTestSuite::WifiHeInfoElemsTestSuite()
+    : TestSuite("wifi-he-info-elems", Type::UNIT)
+{
+    AddTestCase(new HeOperationElementTest, TestCase::Duration::QUICK);
+    AddTestCase(new He6GhzBandCapabilitiesTest, TestCase::Duration::QUICK);
+}
+
+static WifiHeInfoElemsTestSuite g_wifiHeInfoElemsTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-ie-fragment-test.cc ns-3.42/src/wifi/test/wifi-ie-fragment-test.cc
--- ns-3.41/src/wifi/test/wifi-ie-fragment-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-ie-fragment-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -600,10 +600,10 @@
 };
 
 WifiIeFragmentationTestSuite::WifiIeFragmentationTestSuite()
-    : TestSuite("wifi-ie-fragment", UNIT)
+    : TestSuite("wifi-ie-fragment", Type::UNIT)
 {
-    AddTestCase(new WifiIeFragmentationTest(false), TestCase::QUICK);
-    AddTestCase(new WifiIeFragmentationTest(true), TestCase::QUICK);
+    AddTestCase(new WifiIeFragmentationTest(false), TestCase::Duration::QUICK);
+    AddTestCase(new WifiIeFragmentationTest(true), TestCase::Duration::QUICK);
 }
 
 static WifiIeFragmentationTestSuite g_wifiIeFragmentationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-mac-ofdma-test.cc ns-3.42/src/wifi/test/wifi-mac-ofdma-test.cc
--- ns-3.41/src/wifi/test/wifi-mac-ofdma-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-mac-ofdma-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -192,9 +192,9 @@
 
         if (!GetHeFem(SINGLE_LINK_OP_ID)->TryAddMpdu(item, m_txParams, m_availableTime) ||
             (m_availableTime != Time::Min() &&
-             m_txParams.m_protection->protectionTime + m_txParams.m_txDuration // TF tx time
+             *m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // TF tx time
                      + m_apMac->GetWifiPhy()->GetSifs() + duration +
-                     m_txParams.m_acknowledgment->acknowledgmentTime >
+                     *m_txParams.m_acknowledgment->acknowledgmentTime >
                  m_availableTime))
         {
             NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
@@ -367,7 +367,6 @@
 
 /**
  * \ingroup wifi-test
- * \ingroup tests
  * The scenarios
  */
 enum class WifiOfdmaScenario : uint8_t
@@ -2284,7 +2283,7 @@
 };
 
 WifiMacOfdmaTestSuite::WifiMacOfdmaTestSuite()
-    : TestSuite("wifi-mac-ofdma", UNIT)
+    : TestSuite("wifi-mac-ofdma", Type::UNIT)
 {
     using MuEdcaParams = std::initializer_list<OfdmaAckSequenceTest::MuEdcaParameterSet>;
 
@@ -2302,7 +2301,7 @@
                                                  15,
                                                  muEdcaParameterSet,
                                                  scenario),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new OfdmaAckSequenceTest(20,
                                                  WifiAcknowledgment::DL_MU_AGGREGATE_TF,
                                                  10000,
@@ -2310,7 +2309,7 @@
                                                  15,
                                                  muEdcaParameterSet,
                                                  scenario),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new OfdmaAckSequenceTest(20,
                                                  WifiAcknowledgment::DL_MU_TF_MU_BAR,
                                                  10000,
@@ -2318,7 +2317,7 @@
                                                  15,
                                                  muEdcaParameterSet,
                                                  scenario),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new OfdmaAckSequenceTest(40,
                                                  WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE,
                                                  10000,
@@ -2326,7 +2325,7 @@
                                                  15,
                                                  muEdcaParameterSet,
                                                  scenario),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new OfdmaAckSequenceTest(40,
                                                  WifiAcknowledgment::DL_MU_AGGREGATE_TF,
                                                  10000,
@@ -2334,7 +2333,7 @@
                                                  15,
                                                  muEdcaParameterSet,
                                                  scenario),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             AddTestCase(new OfdmaAckSequenceTest(40,
                                                  WifiAcknowledgment::DL_MU_TF_MU_BAR,
                                                  10000,
@@ -2342,7 +2341,7 @@
                                                  15,
                                                  muEdcaParameterSet,
                                                  scenario),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
         }
     }
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-mac-queue-test.cc ns-3.42/src/wifi/test/wifi-mac-queue-test.cc
--- ns-3.41/src/wifi/test/wifi-mac-queue-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-mac-queue-test.cc	2024-05-29 15:29:47.216073800 -0700
@@ -441,10 +441,10 @@
 };
 
 WifiMacQueueTestSuite::WifiMacQueueTestSuite()
-    : TestSuite("wifi-mac-queue", UNIT)
+    : TestSuite("wifi-mac-queue", Type::UNIT)
 {
-    AddTestCase(new WifiMacQueueDropOldestTest, TestCase::QUICK);
-    AddTestCase(new WifiExtractExpiredMpdusTest, TestCase::QUICK);
+    AddTestCase(new WifiMacQueueDropOldestTest, TestCase::Duration::QUICK);
+    AddTestCase(new WifiExtractExpiredMpdusTest, TestCase::Duration::QUICK);
 }
 
 static WifiMacQueueTestSuite g_wifiMacQueueTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-mlo-test.cc ns-3.42/src/wifi/test/wifi-mlo-test.cc
--- ns-3.41/src/wifi/test/wifi-mlo-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-mlo-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -216,6 +216,11 @@
         void Enqueue(Ptr<Packet> packet, Mac48Address to) override
         {
         }
+
+      private:
+        void DoCompleteConfig() override
+        {
+        }
     };
 
   public:
@@ -359,6 +364,16 @@
                           double txPowerW);
 
     /**
+     * Check that the expected Capabilities information elements are present in the given
+     * management frame based on the band in which the given link is operating.
+     *
+     * \param mpdu the given management frame
+     * \param mac the MAC transmitting the management frame
+     * \param phyId the ID of the PHY transmitting the management frame
+     */
+    void CheckCapabilities(Ptr<WifiMpdu> mpdu, Ptr<WifiMac> mac, uint8_t phyId);
+
+    /**
      * Function to trace packets received by the server application
      * \param nodeId the ID of the node that received the packet
      * \param p the packet
@@ -576,11 +591,92 @@
             ss << "} TID = " << +psdu->GetHeader(0).GetQosTid();
         }
         NS_LOG_INFO(ss.str());
+
+        CheckCapabilities(*psdu->begin(), mac, phyId);
     }
     NS_LOG_INFO("TXVECTOR = " << txVector << "\n");
 }
 
 void
+MultiLinkOperationsTestBase::CheckCapabilities(Ptr<WifiMpdu> mpdu, Ptr<WifiMac> mac, uint8_t phyId)
+{
+    auto band = mac->GetDevice()->GetPhy(phyId)->GetPhyBand();
+    bool hasHtCapabilities;
+    bool hasVhtCapabilities;
+    bool hasHeCapabilities;
+    bool hasHe6GhzCapabilities;
+    bool hasEhtCapabilities;
+
+    auto findCapabilities = [&](auto&& frame) {
+        hasHtCapabilities = frame.template Get<HtCapabilities>().has_value();
+        hasVhtCapabilities = frame.template Get<VhtCapabilities>().has_value();
+        hasHeCapabilities = frame.template Get<HeCapabilities>().has_value();
+        hasHe6GhzCapabilities = frame.template Get<He6GhzBandCapabilities>().has_value();
+        hasEhtCapabilities = frame.template Get<EhtCapabilities>().has_value();
+    };
+
+    switch (mpdu->GetHeader().GetType())
+    {
+    case WIFI_MAC_MGT_BEACON: {
+        MgtBeaconHeader beacon;
+        mpdu->GetPacket()->PeekHeader(beacon);
+        findCapabilities(beacon);
+    }
+    break;
+
+    case WIFI_MAC_MGT_PROBE_REQUEST: {
+        MgtProbeRequestHeader probeReq;
+        mpdu->GetPacket()->PeekHeader(probeReq);
+        findCapabilities(probeReq);
+    }
+    break;
+
+    case WIFI_MAC_MGT_PROBE_RESPONSE: {
+        MgtProbeResponseHeader probeResp;
+        mpdu->GetPacket()->PeekHeader(probeResp);
+        findCapabilities(probeResp);
+    }
+    break;
+
+    case WIFI_MAC_MGT_ASSOCIATION_REQUEST: {
+        MgtAssocRequestHeader assocReq;
+        mpdu->GetPacket()->PeekHeader(assocReq);
+        findCapabilities(assocReq);
+    }
+    break;
+
+    case WIFI_MAC_MGT_ASSOCIATION_RESPONSE: {
+        MgtAssocResponseHeader assocResp;
+        mpdu->GetPacket()->PeekHeader(assocResp);
+        findCapabilities(assocResp);
+    }
+    break;
+
+    default:
+        return;
+    }
+
+    NS_TEST_EXPECT_MSG_EQ(
+        hasHtCapabilities,
+        (band != WIFI_PHY_BAND_6GHZ),
+        "HT Capabilities should not be present in a mgt frame sent in 6 GHz band");
+    NS_TEST_EXPECT_MSG_EQ(
+        hasVhtCapabilities,
+        (band == WIFI_PHY_BAND_5GHZ),
+        "VHT Capabilities should only be present in a mgt frame sent in 5 GHz band");
+    NS_TEST_EXPECT_MSG_EQ(hasHeCapabilities,
+                          true,
+                          "HE Capabilities should always be present in a mgt frame");
+    NS_TEST_EXPECT_MSG_EQ(
+        hasHe6GhzCapabilities,
+        (band == WIFI_PHY_BAND_6GHZ),
+        "HE 6GHz Band Capabilities should only be present in a mgt frame sent in 6 GHz band");
+    NS_TEST_EXPECT_MSG_EQ(hasEhtCapabilities,
+                          true,
+                          "EHT Capabilities should always be present in a mgt frame");
+}
+
+void
 MultiLinkOperationsTestBase::L7Receive(uint8_t nodeId, Ptr<const Packet> p, const Address& addr)
 {
     NS_LOG_INFO("Packet received by NODE " << +nodeId << "\n");
@@ -827,7 +923,7 @@
     MultiLinkSetupTest(const BaseParams& baseParams,
                        WifiScanType scanType,
                        const std::vector<uint8_t>& setupLinks,
-                       uint8_t apNegSupport,
+                       WifiTidToLinkMappingNegSupport apNegSupport,
                        const std::string& dlTidToLinkMapping,
                        const std::string& ulTidToLinkMapping);
     ~MultiLinkSetupTest() override = default;
@@ -845,7 +941,9 @@
     void CheckMlSetup();
 
     /**
-     * Check that links that are not setup on the non-AP MLD are disabled.
+     * Check that links that are not setup on the non-AP MLD are disabled. Also, on the AP side,
+     * check that the queue storing QoS data frames destined to the non-AP MLD has a mask for a
+     * link if and only if the link has been setup by the non-AO MLD.
      */
     void CheckDisabledLinks();
 
@@ -892,8 +990,9 @@
 
     const std::vector<uint8_t> m_setupLinks; //!< IDs of the expected links to setup
     WifiScanType m_scanType;                 //!< the scan type (active or passive)
-    std::size_t m_nProbeResp;          //!< number of Probe Responses received by the non-AP MLD
-    uint8_t m_apNegSupport;            //!< TID-to-Link Mapping negotiation supported by the AP MLD
+    std::size_t m_nProbeResp; //!< number of Probe Responses received by the non-AP MLD
+    WifiTidToLinkMappingNegSupport
+        m_apNegSupport;                //!< TID-to-Link Mapping negotiation supported by the AP MLD
     std::string m_dlTidLinkMappingStr; //!< DL TID-to-Link Mapping for non-AP MLD EHT configuration
     std::string m_ulTidLinkMappingStr; //!< UL TID-to-Link Mapping for non-AP MLD EHT configuration
     WifiTidLinkMapping m_dlTidLinkMapping; //!< expected DL TID-to-Link Mapping requested by non-AP
@@ -913,7 +1012,7 @@
 MultiLinkSetupTest::MultiLinkSetupTest(const BaseParams& baseParams,
                                        WifiScanType scanType,
                                        const std::vector<uint8_t>& setupLinks,
-                                       uint8_t apNegSupport,
+                                       WifiTidToLinkMappingNegSupport apNegSupport,
                                        const std::string& dlTidToLinkMapping,
                                        const std::string& ulTidToLinkMapping)
     : MultiLinkOperationsTestBase("Check correctness of Multi-Link Setup", 1, baseParams),
@@ -932,14 +1031,13 @@
     MultiLinkOperationsTestBase::DoSetup();
 
     m_staMacs[0]->SetAttribute("ActiveProbing", BooleanValue(m_scanType == WifiScanType::ACTIVE));
-    m_apMac->GetEhtConfiguration()->SetAttribute(
-        "TidToLinkMappingNegSupport",
-        EnumValue(static_cast<WifiTidToLinkMappingNegSupport>(m_apNegSupport)));
+    m_apMac->GetEhtConfiguration()->SetAttribute("TidToLinkMappingNegSupport",
+                                                 EnumValue(m_apNegSupport));
     // For non-AP MLD, it does not make sense to set the negotiation type to 0 (unless the AP MLD
     // also advertises 0) or 1 (the AP MLD is discarded if it advertises a support of 3)
     auto staEhtConfig = m_staMacs[0]->GetEhtConfiguration();
     staEhtConfig->SetAttribute("TidToLinkMappingNegSupport",
-                               EnumValue(WIFI_TID_TO_LINK_MAPPING_ANY_LINK_SET));
+                               EnumValue(WifiTidToLinkMappingNegSupport::ANY_LINK_SET));
     staEhtConfig->SetAttribute("TidToLinkMappingDl", StringValue(m_dlTidLinkMappingStr));
     staEhtConfig->SetAttribute("TidToLinkMappingUl", StringValue(m_ulTidLinkMappingStr));
 
@@ -950,8 +1048,8 @@
     m_dlTidLinkMapping = staEhtConfig->GetTidLinkMapping(WifiDirection::DOWNLINK);
     m_ulTidLinkMapping = staEhtConfig->GetTidLinkMapping(WifiDirection::UPLINK);
 
-    if (m_apNegSupport == 0 ||
-        (m_apNegSupport == 1 &&
+    if (m_apNegSupport == WifiTidToLinkMappingNegSupport::NOT_SUPPORTED ||
+        (m_apNegSupport == WifiTidToLinkMappingNegSupport::SAME_LINK_SET &&
          !TidToLinkMappingValidForNegType1(m_dlTidLinkMapping, m_ulTidLinkMapping)))
     {
         m_dlTidLinkMapping.clear(); // default link mapping
@@ -1343,7 +1441,8 @@
     // A TID-to-Link Mapping IE is included in the Association Request if and only if the AP MLD
     // and the non-AP MLD are performing ML setup (i.e., they both have multiple links) and the
     // AP MLD advertises a non-null negotiation support type
-    if (m_apMac->GetNLinks() == 1 || m_staMacs[0]->GetNLinks() == 1 || m_apNegSupport == 0)
+    if (m_apMac->GetNLinks() == 1 || m_staMacs[0]->GetNLinks() == 1 ||
+        m_apNegSupport == WifiTidToLinkMappingNegSupport::NOT_SUPPORTED)
     {
         NS_TEST_EXPECT_MSG_EQ(tlm.empty(),
                               true,
@@ -1571,8 +1670,8 @@
             }
         };
 
-    auto storedMapping =
-        m_apMac->GetNLinks() > 1 && m_staMacs[0]->GetNLinks() > 1 && m_apNegSupport > 0;
+    auto storedMapping = m_apMac->GetNLinks() > 1 && m_staMacs[0]->GetNLinks() > 1 &&
+                         m_apNegSupport > WifiTidToLinkMappingNegSupport::NOT_SUPPORTED;
     checkStoredMapping(m_apMac, m_staMacs[0], WifiDirection::DOWNLINK, storedMapping);
     checkStoredMapping(m_apMac, m_staMacs[0], WifiDirection::UPLINK, storedMapping);
     checkStoredMapping(m_staMacs[0], m_apMac, WifiDirection::DOWNLINK, storedMapping);
@@ -1582,6 +1681,25 @@
 void
 MultiLinkSetupTest::CheckDisabledLinks()
 {
+    if (m_apMac->GetNLinks() > 1)
+    {
+        WifiContainerQueueId queueId(WIFI_QOSDATA_QUEUE,
+                                     WIFI_UNICAST,
+                                     m_staMacs[0]->GetAddress(),
+                                     0);
+
+        for (uint8_t linkId = 0; linkId < m_apMac->GetNLinks(); ++linkId)
+        {
+            auto it = std::find(m_setupLinks.cbegin(), m_setupLinks.cend(), linkId);
+
+            // the queue on the AP should have a mask if and only if the link has been setup
+            auto mask = m_apMac->GetMacQueueScheduler()->GetQueueLinkMask(AC_BE, queueId, linkId);
+            NS_TEST_EXPECT_MSG_EQ(mask.has_value(),
+                                  (it != m_setupLinks.cend()),
+                                  "Unexpected presence/absence of mask on link " << +linkId);
+        }
+    }
+
     if (m_staMacs[0]->GetNLinks() == 1)
     {
         // no link is disabled on a single link device
@@ -3114,16 +3232,16 @@
 };
 
 WifiMultiLinkOperationsTestSuite::WifiMultiLinkOperationsTestSuite()
-    : TestSuite("wifi-mlo", UNIT)
+    : TestSuite("wifi-mlo", Type::UNIT)
 {
     using ParamsTuple = std::tuple<MultiLinkOperationsTestBase::BaseParams, // base config params
-                                   std::vector<uint8_t>, // link ID of setup links
-                                   uint8_t,              // AP negotiation support
-                                   std::string,          // DL TID-to-Link Mapping
-                                   std::string>;         // UL TID-to-Link Mapping
+                                   std::vector<uint8_t>,           // link ID of setup links
+                                   WifiTidToLinkMappingNegSupport, // AP negotiation support
+                                   std::string,                    // DL TID-to-Link Mapping
+                                   std::string>;                   // UL TID-to-Link Mapping
 
-    AddTestCase(new GetRnrLinkInfoTest(), TestCase::QUICK);
-    AddTestCase(new MldSwapLinksTest(), TestCase::QUICK);
+    AddTestCase(new GetRnrLinkInfoTest(), TestCase::Duration::QUICK);
+    AddTestCase(new MldSwapLinksTest(), TestCase::Duration::QUICK);
 
     for (const auto& [baseParams,
                       setupLinks,
@@ -3131,28 +3249,31 @@
                       dlTidLinkMapping,
                       ulTidLinkMapping] :
          {// matching channels: setup all links
-          ParamsTuple({{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
-                       {"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
-                       {}},
-                      {0, 1, 2},
-                      0, // AP MLD does not support TID-to-Link Mapping negotiation
-                      "0,1,2,3  0,1,2;  4,5  0,1", // default mapping used instead
-                      "0,1,2,3  1,2;    6,7  0,1"  // default mapping used instead
-                      ),
+          ParamsTuple(
+              {{"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
+               {"{36, 0, BAND_5GHZ, 0}", "{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
+               {}},
+              {0, 1, 2},
+              WifiTidToLinkMappingNegSupport::NOT_SUPPORTED, // AP MLD does not support TID-to-Link
+                                                             // Mapping negotiation
+              "0,1,2,3  0,1,2;  4,5  0,1",                   // default mapping used instead
+              "0,1,2,3  1,2;    6,7  0,1"                    // default mapping used instead
+              ),
           // non-matching channels, matching PHY bands: setup all links
           ParamsTuple({{"{108, 0, BAND_5GHZ, 0}", "{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}"},
                        {"{36, 0, BAND_5GHZ, 0}", "{120, 0, BAND_5GHZ, 0}", "{5, 0, BAND_6GHZ, 0}"},
                        {}},
                       {0, 1, 2},
-                      1, // AP MLD does not support distinct link sets for TIDs
-                      "0,1,2,3  0,1,2;  4,5  0,1", // default mapping used instead
+                      WifiTidToLinkMappingNegSupport::SAME_LINK_SET, // AP MLD does not support
+                                                                     // distinct link sets for TIDs
+                      "0,1,2,3  0,1,2;  4,5  0,1",                   // default mapping used instead
                       ""),
           // non-AP MLD switches band on some links to setup 3 links
           ParamsTuple({{"{2, 0, BAND_2_4GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{36, 0, BAND_5GHZ, 0}"},
                        {"{36, 0, BAND_5GHZ, 0}", "{9, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                        {}},
                       {0, 1, 2},
-                      3,
+                      WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
                       "0,1,2,3  0;  4,5,6,7  1,2", // frames of two TIDs are generated
                       "0,2,3  1,2;  1,4,5,6,7  0"  // frames of two TIDs are generated
                       ),
@@ -3163,7 +3284,8 @@
                {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                {0}},
               {0, 1},
-              1, // AP MLD does not support distinct link sets for TIDs
+              WifiTidToLinkMappingNegSupport::SAME_LINK_SET, // AP MLD does not support distinct
+                                                             // link sets for TIDs
               "0,1,2,3,4,5,6,7  0",
               "0,1,2,3,4,5,6,7  0"),
           // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
@@ -3174,7 +3296,7 @@
                {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                {0, 1}},
               {0, 1},
-              3,
+              WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
               "0,1,2,3  1",
               "0,1,2,3  1"),
           // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
@@ -3186,7 +3308,7 @@
                        {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                        {0, 1, 2}},
                       {0, 2},
-                      3,
+                      WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
                       "",
                       ""),
           // the first link of the non-AP MLD cannot change PHY band and no AP is operating on
@@ -3196,7 +3318,7 @@
                        {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                        {0, 1}},
                       {2},
-                      3,
+                      WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
                       "",
                       ""),
           // non-AP MLD has only two STAs and setups two links
@@ -3204,7 +3326,7 @@
                        {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                        {}},
                       {1, 0},
-                      3,
+                      WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
                       "0,1,2,3  1",
                       ""),
           // single link non-AP STA associates with an AP affiliated with an AP MLD
@@ -3212,7 +3334,7 @@
                        {"{36, 0, BAND_5GHZ, 0}", "{1, 0, BAND_6GHZ, 0}", "{120, 0, BAND_5GHZ, 0}"},
                        {}},
                       {2}, // link ID of AP MLD only (non-AP STA is single link)
-                      3,
+                      WifiTidToLinkMappingNegSupport::ANY_LINK_SET,
                       "",
                       ""),
           // a STA affiliated with a non-AP MLD associates with a single link AP
@@ -3220,7 +3342,7 @@
                        {"{120, 0, BAND_5GHZ, 0}"},
                        {}},
                       {2}, // link ID of non-AP MLD only (AP is single link)
-                      0,
+                      WifiTidToLinkMappingNegSupport::NOT_SUPPORTED,
                       "0,1,2,3  0,1;  4,5,6,7  0,1", // ignored by single link AP
                       "")})
     {
@@ -3230,14 +3352,14 @@
                                            apNegSupport,
                                            dlTidLinkMapping,
                                            ulTidLinkMapping),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
         AddTestCase(new MultiLinkSetupTest(baseParams,
                                            WifiScanType::ACTIVE,
                                            setupLinks,
                                            apNegSupport,
                                            dlTidLinkMapping,
                                            ulTidLinkMapping),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
 
         for (const auto& trafficPattern : {WifiTrafficPattern::STA_TO_STA,
                                            WifiTrafficPattern::STA_TO_AP,
@@ -3251,7 +3373,7 @@
                                             WifiBaEnabled::NO,
                                             WifiUseBarAfterMissedBa::NO,
                                             1),
-                        TestCase::QUICK);
+                        TestCase::Duration::QUICK);
             for (const auto& useBarAfterMissedBa :
                  {WifiUseBarAfterMissedBa::YES, WifiUseBarAfterMissedBa::NO})
             {
@@ -3261,14 +3383,14 @@
                                                 WifiBaEnabled::YES,
                                                 useBarAfterMissedBa,
                                                 1),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
                 // Block Ack agreement with nMaxInflight=2
                 AddTestCase(new MultiLinkTxTest(baseParams,
                                                 trafficPattern,
                                                 WifiBaEnabled::YES,
                                                 useBarAfterMissedBa,
                                                 2),
-                            TestCase::QUICK);
+                            TestCase::Duration::QUICK);
             }
         }
 
@@ -3283,16 +3405,16 @@
                 // Block Ack agreement with nMaxInflight=1
                 AddTestCase(
                     new MultiLinkMuTxTest(baseParams, muTrafficPattern, useBarAfterMissedBa, 1),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
                 // Block Ack agreement with nMaxInflight=2
                 AddTestCase(
                     new MultiLinkMuTxTest(baseParams, muTrafficPattern, useBarAfterMissedBa, 2),
-                    TestCase::QUICK);
+                    TestCase::Duration::QUICK);
             }
         }
     }
 
-    AddTestCase(new ReleaseSeqNoAfterCtsTimeoutTest(), TestCase::QUICK);
+    AddTestCase(new ReleaseSeqNoAfterCtsTimeoutTest(), TestCase::Duration::QUICK);
 }
 
 static WifiMultiLinkOperationsTestSuite g_wifiMultiLinkOperationsTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-non-ht-dup-test.cc ns-3.42/src/wifi/test/wifi-non-ht-dup-test.cc
--- ns-3.41/src/wifi/test/wifi-non-ht-dup-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-non-ht-dup-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -29,12 +29,15 @@
 #include "ns3/nist-error-rate-model.h"
 #include "ns3/node.h"
 #include "ns3/non-communicating-net-device.h"
+#include "ns3/pointer.h"
 #include "ns3/rng-seed-manager.h"
 #include "ns3/simulator.h"
 #include "ns3/spectrum-wifi-helper.h"
 #include "ns3/spectrum-wifi-phy.h"
 #include "ns3/sta-wifi-mac.h"
+#include "ns3/string.h"
 #include "ns3/test.h"
+#include "ns3/txop.h"
 #include "ns3/waveform-generator.h"
 #include "ns3/wifi-mac-header.h"
 #include "ns3/wifi-net-device.h"
@@ -870,7 +873,9 @@
 
     auto apNode = CreateObject<Node>();
     auto apDev = CreateObject<WifiNetDevice>();
-    auto apMac = CreateObject<ApWifiMac>();
+    auto apMac = CreateObjectWithAttributes<ApWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
     apDev->SetMac(apMac);
     m_phyAp = CreateObject<MuRtsCtsSpectrumWifiPhy>();
@@ -1046,7 +1051,7 @@
 };
 
 WifiNonHtDuplicateTestSuite::WifiNonHtDuplicateTestSuite()
-    : TestSuite("wifi-non-ht-dup", UNIT)
+    : TestSuite("wifi-non-ht-dup", Type::UNIT)
 {
     /**
      * Channel map:
@@ -1088,7 +1093,7 @@
                                                    {{WIFI_STANDARD_80211a, 5180, 0},
                                                     {WIFI_STANDARD_80211n, 5200, 0},
                                                     {WIFI_STANDARD_80211ac, 5230, 0}}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     /* same channel map and test scenario as previously but inject interference on channel 40 */
     AddTestCase(new TestNonHtDuplicatePhyReception(WIFI_STANDARD_80211ax,
                                                    5210,
@@ -1097,35 +1102,44 @@
                                                     {WIFI_STANDARD_80211n, 5200, 0},
                                                     {WIFI_STANDARD_80211ac, 5230, 0}},
                                                    {false, true, false, false}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     /* test PHY reception of multiple CTS responses following a MU-RTS */
     /* 4 STAs operating on 20 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{20}, {20}, {20}, {20}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{20}, {20}, {20}, {20}}),
+                TestCase::Duration::QUICK);
     /* 4 STAs operating on 40 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40}, {40}, {40}, {40}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40}, {40}, {40}, {40}}),
+                TestCase::Duration::QUICK);
     /* 4 STAs operating on 80 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80}, {80}, {80}, {80}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80}, {80}, {80}, {80}}),
+                TestCase::Duration::QUICK);
     /* 4 STAs operating on 160 MHz */
     AddTestCase(new TestMultipleCtsResponsesFromMuRts({{160}, {160}, {160}, {160}}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
     /* 4 STAs operating on different bandwidths with PPDUs sent with decreasing BW: 160, 80, 40 and
      * 20 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{160}, {80}, {40}, {20}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{160}, {80}, {40}, {20}}),
+                TestCase::Duration::QUICK);
     /* 4 STAs operating on different bandwidths with PPDUs sent with increasing BW: 20, 40, 80 and
      * 160 MHz */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{20}, {40}, {80}, {160}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{20}, {40}, {80}, {160}}),
+                TestCase::Duration::QUICK);
     /* 2 STAs operating on different bandwidths with PPDUs sent with decreasing BW but the first STA
      * does not respond */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80, true}, {40, false}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80, true}, {40, false}}),
+                TestCase::Duration::QUICK);
     /* 2 STAs operating on different bandwidths with PPDUs sent with decreasing BW but the second
      * STA does not respond */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80, false}, {40, true}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{80, false}, {40, true}}),
+                TestCase::Duration::QUICK);
     /* 2 STAs operating on different bandwidths with PPDUs sent with increasing BW but the first STA
      * does not respond */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40, true}, {80, false}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40, true}, {80, false}}),
+                TestCase::Duration::QUICK);
     /* 2 STAs operating on different bandwidths with PPDUs sent with increasing BW but the second
      * STA does not respond */
-    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40, false}, {80, true}}), TestCase::QUICK);
+    AddTestCase(new TestMultipleCtsResponsesFromMuRts({{40, false}, {80, true}}),
+                TestCase::Duration::QUICK);
 }
 
 static WifiNonHtDuplicateTestSuite wifiNonHtDuplicateTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-phy-cca-test.cc ns-3.42/src/wifi/test/wifi-phy-cca-test.cc
--- ns-3.41/src/wifi/test/wifi-phy-cca-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-phy-cca-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -765,8 +765,8 @@
      */
     struct StateCheckPoint
     {
-        Time timePoint{Seconds(0)};          //!< time at which the check will performed
-        WifiPhyState expectedPhyState{IDLE}; //!< expected PHY state
+        Time timePoint{Seconds(0)}; //!< time at which the check will performed
+        WifiPhyState expectedPhyState{WifiPhyState::IDLE}; //!< expected PHY state
     };
 
     /**
@@ -2942,10 +2942,10 @@
 };
 
 WifiPhyCcaTestSuite::WifiPhyCcaTestSuite()
-    : TestSuite("wifi-phy-cca", UNIT)
+    : TestSuite("wifi-phy-cca", Type::UNIT)
 {
-    AddTestCase(new WifiPhyCcaThresholdsTest, TestCase::QUICK);
-    AddTestCase(new WifiPhyCcaIndicationTest, TestCase::QUICK);
+    AddTestCase(new WifiPhyCcaThresholdsTest, TestCase::Duration::QUICK);
+    AddTestCase(new WifiPhyCcaIndicationTest, TestCase::Duration::QUICK);
 }
 
 static WifiPhyCcaTestSuite WifiPhyCcaTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-phy-mu-mimo-test.cc ns-3.42/src/wifi/test/wifi-phy-mu-mimo-test.cc
--- ns-3.41/src/wifi/test/wifi-phy-mu-mimo-test.cc	2024-02-09 14:44:08.613795300 -0800
+++ ns-3.42/src/wifi/test/wifi-phy-mu-mimo-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -32,7 +32,9 @@
 #include "ns3/simulator.h"
 #include "ns3/spectrum-wifi-helper.h"
 #include "ns3/spectrum-wifi-phy.h"
+#include "ns3/string.h"
 #include "ns3/test.h"
+#include "ns3/txop.h"
 #include "ns3/uinteger.h"
 #include "ns3/wifi-mac-header.h"
 #include "ns3/wifi-net-device.h"
@@ -1555,7 +1557,9 @@
     Ptr<Node> apNode = CreateObject<Node>();
     Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
     apDev->SetStandard(WIFI_STANDARD_80211ax);
-    Ptr<ApWifiMac> apMac = CreateObject<ApWifiMac>();
+    auto apMac = CreateObjectWithAttributes<ApWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
     apDev->SetMac(apMac);
     m_phyAp = CreateObject<MuMimoSpectrumWifiPhy>(0);
@@ -1860,11 +1864,11 @@
 };
 
 WifiPhyMuMimoTestSuite::WifiPhyMuMimoTestSuite()
-    : TestSuite("wifi-phy-mu-mimo", UNIT)
+    : TestSuite("wifi-phy-mu-mimo", Type::UNIT)
 {
-    AddTestCase(new TestDlMuTxVector, TestCase::QUICK);
-    AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::QUICK);
-    AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::QUICK);
+    AddTestCase(new TestDlMuTxVector, TestCase::Duration::QUICK);
+    AddTestCase(new TestDlMuMimoPhyTransmission, TestCase::Duration::QUICK);
+    AddTestCase(new TestUlMuMimoPhyTransmission, TestCase::Duration::QUICK);
 }
 
 static WifiPhyMuMimoTestSuite WifiPhyMuMimoTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-phy-ofdma-test.cc ns-3.42/src/wifi/test/wifi-phy-ofdma-test.cc
--- ns-3.41/src/wifi/test/wifi-phy-ofdma-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-phy-ofdma-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -41,6 +41,7 @@
 #include "ns3/string.h"
 #include "ns3/test.h"
 #include "ns3/threshold-preamble-detection-model.h"
+#include "ns3/txop.h"
 #include "ns3/waveform-generator.h"
 #include "ns3/wifi-mac-header.h"
 #include "ns3/wifi-net-device.h"
@@ -2501,7 +2502,9 @@
     m_phy = CreateObject<OfdmaSpectrumWifiPhy>(0);
     Ptr<InterferenceHelper> interferenceHelper = CreateObject<InterferenceHelper>();
     Ptr<ErrorRateModel> error = CreateObject<NistErrorRateModel>();
-    Ptr<ApWifiMac> mac = CreateObject<ApWifiMac>();
+    auto mac = CreateObjectWithAttributes<ApWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     mac->SetAttribute("BeaconGeneration", BooleanValue(false));
     dev->SetMac(mac);
     m_phy->SetInterferenceHelper(interferenceHelper);
@@ -3716,7 +3719,9 @@
     Ptr<Node> apNode = CreateObject<Node>();
     Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
     apDev->SetStandard(WIFI_STANDARD_80211ax);
-    Ptr<ApWifiMac> apMac = CreateObject<ApWifiMac>();
+    auto apMac = CreateObjectWithAttributes<ApWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
     apDev->SetMac(apMac);
     m_phyAp = CreateObject<OfdmaSpectrumWifiPhy>(0);
@@ -5074,7 +5079,9 @@
 
     Ptr<Node> apNode = CreateObject<Node>();
     Ptr<WifiNetDevice> apDev = CreateObject<WifiNetDevice>();
-    Ptr<ApWifiMac> apMac = CreateObject<ApWifiMac>();
+    auto apMac = CreateObjectWithAttributes<ApWifiMac>(
+        "Txop",
+        PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
     apMac->SetAttribute("BeaconGeneration", BooleanValue(false));
     apDev->SetMac(apMac);
     m_phyAp = CreateObject<OfdmaSpectrumWifiPhy>(0);
@@ -5838,15 +5845,15 @@
 };
 
 WifiPhyOfdmaTestSuite::WifiPhyOfdmaTestSuite()
-    : TestSuite("wifi-phy-ofdma", UNIT)
+    : TestSuite("wifi-phy-ofdma", Type::UNIT)
 {
-    AddTestCase(new TestDlOfdmaPhyTransmission, TestCase::QUICK);
-    AddTestCase(new TestDlOfdmaPhyPuncturing, TestCase::QUICK);
-    AddTestCase(new TestUlOfdmaPpduUid, TestCase::QUICK);
-    AddTestCase(new TestMultipleHeTbPreambles, TestCase::QUICK);
-    AddTestCase(new TestUlOfdmaPhyTransmission, TestCase::QUICK);
-    AddTestCase(new TestPhyPaddingExclusion, TestCase::QUICK);
-    AddTestCase(new TestUlOfdmaPowerControl, TestCase::QUICK);
+    AddTestCase(new TestDlOfdmaPhyTransmission, TestCase::Duration::QUICK);
+    AddTestCase(new TestDlOfdmaPhyPuncturing, TestCase::Duration::QUICK);
+    AddTestCase(new TestUlOfdmaPpduUid, TestCase::Duration::QUICK);
+    AddTestCase(new TestMultipleHeTbPreambles, TestCase::Duration::QUICK);
+    AddTestCase(new TestUlOfdmaPhyTransmission, TestCase::Duration::QUICK);
+    AddTestCase(new TestPhyPaddingExclusion, TestCase::Duration::QUICK);
+    AddTestCase(new TestUlOfdmaPowerControl, TestCase::Duration::QUICK);
 }
 
 static WifiPhyOfdmaTestSuite wifiPhyOfdmaTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-phy-reception-test.cc ns-3.42/src/wifi/test/wifi-phy-reception-test.cc
--- ns-3.41/src/wifi/test/wifi-phy-reception-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-phy-reception-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -4706,12 +4706,15 @@
     /**
      * Callback invoked when the PHY model starts to process a signal
      *
-     * \param signalType whether signal is WiFi (true) or foreign (false)
+     * \param signal the arriving signal
      * \param senderNodeId node Id of the sender of the signal
      * \param rxPower received signal power (dBm)
      * \param duration signal duration
      */
-    void RxBegin(bool signalType, uint32_t senderNodeId, double rxPower, Time duration);
+    void RxBegin(Ptr<const SpectrumSignalParameters> signal,
+                 uint32_t senderNodeId,
+                 double rxPower,
+                 Time duration);
 
     /**
      * Send function (sends a single packet)
@@ -4768,12 +4771,13 @@
 }
 
 void
-TestSpectrumChannelWithBandwidthFilter::RxBegin(bool signalType [[maybe_unused]],
+TestSpectrumChannelWithBandwidthFilter::RxBegin(Ptr<const SpectrumSignalParameters> signal
+                                                [[maybe_unused]],
                                                 uint32_t senderNodeId [[maybe_unused]],
                                                 double rxPower [[maybe_unused]],
                                                 Time duration [[maybe_unused]])
 {
-    NS_LOG_FUNCTION(this << signalType << senderNodeId << rxPower << duration);
+    NS_LOG_FUNCTION(this << signal << senderNodeId << rxPower << duration);
     m_countRxBegin++;
 }
 
@@ -4852,6 +4856,174 @@
  * \ingroup wifi-test
  * \ingroup tests
  *
+ * \brief This test verifies that the WifiPhyRxfailureReason distinguishes between two cases:  1) a
+ * drop due to transmitting during the signal detection interval, and 2) a drop due to transmitting
+ * after the receiver has detected a preamble but is waiting for the end of the preamble. 2
+ * SpectrumWifiPhy are setup and connected on the same spectrum channel. The test will send a packet
+ * over the channel and after a controlled amount of transmit delay (to check both cases) the
+ * receiver of the packet will send its own packet. If delay is less than preamble detection period,
+ * the signal detection should be aborted by transmission. If delay is greater than preamble
+ * detection period, the signal reception should be aborted by transmission.
+ */
+class TestPhyDropDueToTx : public TestCase
+{
+  public:
+    /**
+     * Constructor
+     *
+     * \param delay delay in microseconds to send second packet
+     * \param expectedReason expected failure reason
+     */
+    TestPhyDropDueToTx(Time delay, WifiPhyRxfailureReason expectedReason);
+
+  protected:
+    void DoSetup() override;
+    void DoTeardown() override;
+
+  private:
+    /**
+     * RX dropped function
+     * \param p the packet
+     * \param reason the reason
+     */
+    void PhyDropTraceSink(Ptr<const Packet> p, WifiPhyRxfailureReason reason);
+
+    /**
+     * Send function (sends a single packet)
+     * \param phy the WifiPhy object to send the packet
+     */
+    void Send(Ptr<WifiPhy> phy) const;
+
+    /**
+     * Event scheduled at end of simulation for validation
+     */
+    void CheckDropReason();
+
+    void DoRun() override;
+
+    Ptr<SpectrumWifiPhy> m_phyA{nullptr}; ///< transmit function
+    Ptr<SpectrumWifiPhy> m_phyB{nullptr}; ///< transmit/receive function
+
+    Time m_delay; ///< delay between transmissions in MicroSeconds
+
+    WifiPhyRxfailureReason m_expectedReason; ///< expected WifiPhyRxfailureReason
+    WifiPhyRxfailureReason m_observedReason; ///< observed WifiPhyRxfailureReason
+};
+
+TestPhyDropDueToTx::TestPhyDropDueToTx(Time delay, WifiPhyRxfailureReason expectedReason)
+    : TestCase("Test for correct WifiPhyRxfailureReason from PhyRxDrop trace"),
+      m_delay(delay),
+      m_expectedReason(expectedReason)
+{
+}
+
+void
+TestPhyDropDueToTx::Send(Ptr<WifiPhy> phy) const
+{
+    const auto txVector =
+        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, false);
+
+    auto pkt = Create<Packet>(1000);
+    WifiMacHeader hdr;
+
+    hdr.SetType(WIFI_MAC_QOSDATA);
+    hdr.SetQosTid(0);
+
+    auto psdu = Create<WifiPsdu>(pkt, hdr);
+    phy->Send(psdu, txVector);
+}
+
+void
+TestPhyDropDueToTx::CheckDropReason()
+{
+    NS_TEST_ASSERT_MSG_EQ(m_expectedReason,
+                          m_observedReason,
+                          "Packet was dropped due to the wrong drop reason reported ");
+}
+
+void
+TestPhyDropDueToTx::PhyDropTraceSink(Ptr<const Packet> p, WifiPhyRxfailureReason reason)
+{
+    NS_LOG_FUNCTION(this << p << reason);
+    m_observedReason = reason;
+}
+
+void
+TestPhyDropDueToTx::DoSetup()
+{
+    NS_LOG_FUNCTION(this);
+    auto channel = CreateObject<SingleModelSpectrumChannel>();
+
+    auto node = CreateObject<Node>();
+    auto devA = CreateObject<WifiNetDevice>();
+    m_phyA = CreateObject<SpectrumWifiPhy>();
+    m_phyA->SetDevice(devA);
+    m_phyA->SetTxPowerStart(20);
+    m_phyA->SetTxPowerEnd(20);
+
+    auto nodeRx = CreateObject<Node>();
+    auto devB = CreateObject<WifiNetDevice>();
+    m_phyB = CreateObject<SpectrumWifiPhy>();
+    m_phyB->SetDevice(devB);
+    m_phyB->SetTxPowerStart(20);
+    m_phyB->SetTxPowerEnd(20);
+
+    auto interferenceTx = CreateObject<InterferenceHelper>();
+    m_phyA->SetInterferenceHelper(interferenceTx);
+    auto errorTx = CreateObject<NistErrorRateModel>();
+    m_phyA->SetErrorRateModel(errorTx);
+
+    auto interferenceRx = CreateObject<InterferenceHelper>();
+    m_phyB->SetInterferenceHelper(interferenceRx);
+    auto errorRx = CreateObject<NistErrorRateModel>();
+    m_phyB->SetErrorRateModel(errorRx);
+
+    m_phyA->AddChannel(channel);
+    m_phyB->AddChannel(channel);
+
+    m_phyA->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_phyA->SetOperatingChannel(WifiPhy::ChannelTuple{36, 0, WIFI_PHY_BAND_5GHZ, 0});
+
+    m_phyB->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_phyB->SetOperatingChannel(WifiPhy::ChannelTuple{36, 0, WIFI_PHY_BAND_5GHZ, 0});
+
+    devA->SetPhy(m_phyA);
+    node->AddDevice(devA);
+    devB->SetPhy(m_phyB);
+    nodeRx->AddDevice(devB);
+
+    m_phyB->TraceConnectWithoutContext("PhyRxDrop",
+                                       MakeCallback(&TestPhyDropDueToTx::PhyDropTraceSink, this));
+}
+
+void
+TestPhyDropDueToTx::DoTeardown()
+{
+    m_phyA->Dispose();
+    m_phyB->Dispose();
+}
+
+void
+TestPhyDropDueToTx::DoRun()
+{
+    NS_LOG_FUNCTION(this);
+
+    Simulator::ScheduleNow(&TestPhyDropDueToTx::Send, this, m_phyA);
+    Simulator::Schedule(m_delay, &TestPhyDropDueToTx::Send, this, m_phyB);
+
+    // Upon transmitting the second packet from m_phyB, the reception from
+    // m_phyA will be immediately dropped.  Check the drop reason a short
+    // while later (1 ns is sufficient)
+    Simulator::Schedule(m_delay + NanoSeconds(1), &TestPhyDropDueToTx::CheckDropReason, this);
+
+    Simulator::Run();
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
  * \brief wifi PHY reception Test Suite
  */
 class WifiPhyReceptionTestSuite : public TestSuite
@@ -4861,24 +5033,33 @@
 };
 
 WifiPhyReceptionTestSuite::WifiPhyReceptionTestSuite()
-    : TestSuite("wifi-phy-reception", UNIT)
+    : TestSuite("wifi-phy-reception", Type::UNIT)
 {
-    AddTestCase(new TestThresholdPreambleDetectionWithoutFrameCapture, TestCase::QUICK);
-    AddTestCase(new TestThresholdPreambleDetectionWithFrameCapture, TestCase::QUICK);
-    AddTestCase(new TestSimpleFrameCaptureModel, TestCase::QUICK);
-    AddTestCase(new TestPhyHeadersReception, TestCase::QUICK);
-    AddTestCase(new TestAmpduReception, TestCase::QUICK);
-    AddTestCase(new TestUnsupportedModulationReception(), TestCase::QUICK);
-    AddTestCase(new TestUnsupportedBandwidthReception(), TestCase::QUICK);
-    AddTestCase(new TestPrimary20CoveredByPpdu(), TestCase::QUICK);
+    AddTestCase(new TestThresholdPreambleDetectionWithoutFrameCapture, TestCase::Duration::QUICK);
+    AddTestCase(new TestThresholdPreambleDetectionWithFrameCapture, TestCase::Duration::QUICK);
+    AddTestCase(new TestSimpleFrameCaptureModel, TestCase::Duration::QUICK);
+    AddTestCase(new TestPhyHeadersReception, TestCase::Duration::QUICK);
+    AddTestCase(new TestAmpduReception, TestCase::Duration::QUICK);
+    AddTestCase(new TestUnsupportedModulationReception(), TestCase::Duration::QUICK);
+    AddTestCase(new TestUnsupportedBandwidthReception(), TestCase::Duration::QUICK);
+    AddTestCase(new TestPrimary20CoveredByPpdu(), TestCase::Duration::QUICK);
     // The below three test cases are related.  The test involves a receiver tuned to
     // channel 36 and a transmitter sending on channels 36, 40, and 44, respectively.
     // The second argument corresponds to the number of signals expected to be received.
     // Signals on channel 36 and 40 will fall within the receiver bandwidth, while
     // a signal on channel 44 will fall completely outside and will be filtered.
-    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(36, 1), TestCase::QUICK);
-    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(40, 1), TestCase::QUICK);
-    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(44, 0), TestCase::QUICK);
+    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(36, 1), TestCase::Duration::QUICK);
+    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(40, 1), TestCase::Duration::QUICK);
+    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(44, 0), TestCase::Duration::QUICK);
+    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(36, 1), TestCase::Duration::QUICK);
+    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(40, 1), TestCase::Duration::QUICK);
+    AddTestCase(new TestSpectrumChannelWithBandwidthFilter(44, 0), TestCase::Duration::QUICK);
+    // 4 Microseconds is just less than the preamble detection period since there is no
+    // propagation delay model
+    AddTestCase(new TestPhyDropDueToTx(MicroSeconds(4), SIGNAL_DETECTION_ABORTED_BY_TX),
+                TestCase::Duration::QUICK);
+    AddTestCase(new TestPhyDropDueToTx(MicroSeconds(5), RECEPTION_ABORTED_BY_TX),
+                TestCase::Duration::QUICK);
 }
 
 static WifiPhyReceptionTestSuite wifiPhyReceptionTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-phy-rx-trace-helper-test.cc ns-3.42/src/wifi/test/wifi-phy-rx-trace-helper-test.cc
--- ns-3.41/src/wifi/test/wifi-phy-rx-trace-helper-test.cc	1969-12-31 16:00:00.000000000 -0800
+++ ns-3.42/src/wifi/test/wifi-phy-rx-trace-helper-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -0,0 +1,2489 @@
+/*
+ * Copyright (c) 2023 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "ns3/ampdu-tag.h"
+#include "ns3/ap-wifi-mac.h"
+#include "ns3/boolean.h"
+#include "ns3/config.h"
+#include "ns3/constant-position-mobility-model.h"
+#include "ns3/double.h"
+#include "ns3/eht-configuration.h"
+#include "ns3/he-phy.h"
+#include "ns3/he-ppdu.h"
+#include "ns3/interference-helper.h"
+#include "ns3/log.h"
+#include "ns3/mobility-helper.h"
+#include "ns3/mpdu-aggregator.h"
+#include "ns3/multi-model-spectrum-channel.h"
+#include "ns3/nist-error-rate-model.h"
+#include "ns3/ofdm-ppdu.h"
+#include "ns3/packet-socket-address.h"
+#include "ns3/packet-socket-client.h"
+#include "ns3/packet-socket-helper.h"
+#include "ns3/packet-socket-server.h"
+#include "ns3/pointer.h"
+#include "ns3/rng-seed-manager.h"
+#include "ns3/simple-frame-capture-model.h"
+#include "ns3/single-model-spectrum-channel.h"
+#include "ns3/spectrum-wifi-helper.h"
+#include "ns3/spectrum-wifi-phy.h"
+#include "ns3/test.h"
+#include "ns3/threshold-preamble-detection-model.h"
+#include "ns3/wifi-bandwidth-filter.h"
+#include "ns3/wifi-mac-header.h"
+#include "ns3/wifi-mpdu.h"
+#include "ns3/wifi-net-device.h"
+#include "ns3/wifi-phy-rx-trace-helper.h"
+#include "ns3/wifi-psdu.h"
+#include "ns3/wifi-spectrum-phy-interface.h"
+#include "ns3/wifi-spectrum-signal-parameters.h"
+#include "ns3/wifi-spectrum-value-helper.h"
+#include "ns3/wifi-utils.h"
+#include "ns3/yans-wifi-channel.h"
+#include "ns3/yans-wifi-phy.h"
+#include <ns3/propagation-loss-model.h>
+
+#include <optional>
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE("WifiPhyRxTraceHelperTest");
+
+/**
+ * \ingroup wifi-test
+ * \brief Implements a test case to evaluate the reception process of WiFi Physical Layer (PHY)
+ * frames (PPDU) with multiple MAC Protocol Data Units (MPDUs).
+ *
+ * This class extends the TestCase class to simulate and analyze the reception of PPDUs containing
+ * either one or two MPDUs. It specifically tests the PHY layer's capability to handle multiple
+ * MPDUs addressed to specific receivers, measuring success and failure rates. The simulation setup
+ * includes configuring transmit and receive power levels, and the class provides functionality to
+ * check statistics related to PPDU and MPDU reception success and failure, as well as overlap
+ * handling.
+ */
+class TestWifiPhyRxTraceHelper : public TestCase
+{
+  public:
+    /**
+     * Constructs a TestWifiPhyRxTraceHelper instance with a given test name.
+     * \param test_name The name of the test case.
+     */
+    TestWifiPhyRxTraceHelper(std::string test_name);
+
+    /**
+     * Destructor.
+     */
+    ~TestWifiPhyRxTraceHelper() override = default;
+
+  private:
+    void DoSetup() override;
+    void DoRun() override;
+    void DoTeardown() override;
+
+    /**
+     * Sends a PPDU containing two MPDUs addressed to specific receivers.
+     * \param rxPowerDbm The transmit power in dBm.
+     * \param add1 The MAC address of the first receiver.
+     * \param add2 The MAC address of the second receiver.
+     * \param tx_phy The transmitting PHY object.
+     */
+    void SendPpduWithTwoMpdus(double rxPowerDbm,
+                              Mac48Address add1,
+                              Mac48Address add2,
+                              Ptr<ns3::SpectrumWifiPhy> tx_phy);
+
+    /**
+     * Sends a PPDU containing one MPDU addressed to a specific receiver.
+     * \param rxPowerDbm The transmit power in dBm.
+     * \param add1 The MAC address of the receiver.
+     * \param tx_phy The transmitting PHY object.
+     */
+    void SendPpduWithOneMpdu(double rxPowerDbm,
+                             Mac48Address add1,
+                             Ptr<ns3::SpectrumWifiPhy> tx_phy);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedPpduSuccess The expected number of successful PPDU receptions.
+     * \param expectedPpduFailure The expected number of failed PPDU receptions.
+     * \param expectedMpduSuccess The expected number of successful MPDU receptions within PPDUs.
+     * \param expectedMpduFailure The expected number of failed MPDU receptions within PPDUs.
+     * \param expectedOverlaps The expected number of overlapping reception events.
+     * \param expectedNonOverlaps The expected number of non-overlapping reception events.
+     */
+    void CheckAllStats(uint64_t expectedPpduSuccess,
+                       uint64_t expectedPpduFailure,
+                       uint64_t expectedMpduSuccess,
+                       uint64_t expectedMpduFailure,
+                       uint64_t expectedOverlaps,
+                       uint64_t expectedNonOverlaps);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedStats The expected counts for PPDU and MPDU reception.
+     * @param nodeId The node ID for which to check the received stats.
+     * @param deviceId The device ID for which to check the received stats.
+     * @param linkId The link ID for which to check the received stats.
+     */
+    void CheckStats(WifiPhyTraceStatistics expectedStats,
+                    uint32_t nodeId,
+                    uint32_t deviceId,
+                    uint32_t linkId);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedRecordCount The expected number of records.
+     */
+    void CheckRecords(uint64_t expectedRecordCount);
+
+    Mac48Address wrongReceiver =
+        Mac48Address("00:00:00:00:00:01"); ///< The MAC address representing an incorrect receiver,
+                                           ///< used for testing.
+    Mac48Address correctReceiver =
+        Mac48Address("00:00:00:00:00:03"); ///< The MAC address representing the correct receiver,
+                                           ///< used for testing.
+
+    std::map<ns3::Mac48Address, uint32_t> MacToNodeId = {
+        {Mac48Address("00:00:00:00:00:04"), 0},
+        {Mac48Address("00:00:00:00:00:05"), 1},
+        {correctReceiver, 2},
+        {wrongReceiver, 3}}; ///< Maps MAC addresses to node IDs. This is done since there is no MAC
+                             ///< layer configured and therefore the helper cannot obtain the MAC
+                             ///< addresses automatically.
+
+    Ptr<Node> nodeRx;                    ///< The receiving node
+    Ptr<SpectrumWifiPhy> m_txA{nullptr}; ///< The transmit function for node A.
+    Ptr<SpectrumWifiPhy> m_txB{nullptr}; ///< The transmit function for node B.
+    Ptr<SpectrumWifiPhy> m_rx{nullptr};  ///< The receive function for testing.
+
+    WifiPhyRxTraceHelper
+        m_rxTraceHelper; ///< The helper being tested for tracking PHY reception events.
+};
+
+TestWifiPhyRxTraceHelper::TestWifiPhyRxTraceHelper(std::string test_name)
+    : TestCase{test_name}
+{
+}
+
+void
+TestWifiPhyRxTraceHelper::DoSetup()
+{
+    double txPower = 20;
+
+    auto spectrumChannel = CreateObject<SingleModelSpectrumChannel>();
+
+    auto nodeA = CreateObject<Node>();
+    auto devA = CreateObject<WifiNetDevice>();
+    m_txA = CreateObject<SpectrumWifiPhy>();
+    m_txA->SetDevice(devA);
+    m_txA->SetTxPowerStart(txPower);
+    m_txA->SetTxPowerEnd(txPower);
+
+    auto nodeB = CreateObject<Node>();
+    auto devB = CreateObject<WifiNetDevice>();
+    m_txB = CreateObject<SpectrumWifiPhy>();
+    m_txB->SetDevice(devB);
+    m_txB->SetTxPowerStart(txPower);
+    m_txB->SetTxPowerEnd(txPower);
+
+    nodeRx = CreateObject<Node>();
+    auto devRx = CreateObject<WifiNetDevice>();
+    m_rx = CreateObject<SpectrumWifiPhy>();
+    m_rx->SetDevice(devRx);
+
+    Ptr<InterferenceHelper> interferenceTxA = CreateObject<InterferenceHelper>();
+    m_txA->SetInterferenceHelper(interferenceTxA);
+    auto errorTxA = CreateObject<NistErrorRateModel>();
+    m_txA->SetErrorRateModel(errorTxA);
+
+    auto interferenceTxB = CreateObject<InterferenceHelper>();
+    m_txB->SetInterferenceHelper(interferenceTxB);
+    auto errorTxB = CreateObject<NistErrorRateModel>();
+    m_txB->SetErrorRateModel(errorTxB);
+
+    auto interferenceRx = CreateObject<InterferenceHelper>();
+    m_rx->SetInterferenceHelper(interferenceRx);
+    auto errorRx = CreateObject<NistErrorRateModel>();
+    m_rx->SetErrorRateModel(errorRx);
+
+    m_txA->AddChannel(spectrumChannel);
+    m_txB->AddChannel(spectrumChannel);
+    m_rx->AddChannel(spectrumChannel);
+
+    m_txA->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_txB->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_rx->ConfigureStandard(WIFI_STANDARD_80211ax);
+
+    m_txA->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+    m_txB->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+    m_rx->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+
+    devA->SetPhy(m_txA);
+    nodeA->AddDevice(devA);
+    devB->SetPhy(m_txB);
+    nodeB->AddDevice(devB);
+    devRx->SetPhy(m_rx);
+    nodeRx->AddDevice(devRx);
+
+    NodeContainer nodes;
+    nodes.Add(nodeA);
+    nodes.Add(nodeB);
+    nodes.Add(nodeRx);
+
+    m_rxTraceHelper.Enable(nodes, MacToNodeId);
+
+    auto preambleDetectionModel = CreateObject<ThresholdPreambleDetectionModel>();
+    preambleDetectionModel->SetAttribute("Threshold", DoubleValue(4));
+    preambleDetectionModel->SetAttribute("MinimumRssi", DoubleValue(-82));
+    m_rx->SetPreambleDetectionModel(preambleDetectionModel);
+}
+
+void
+TestWifiPhyRxTraceHelper::DoTeardown()
+{
+    m_txA->Dispose();
+    m_txB->Dispose();
+    m_rx->Dispose();
+}
+
+void
+TestWifiPhyRxTraceHelper::SendPpduWithTwoMpdus(double rxPowerDbm,
+                                               Mac48Address receiver1,
+                                               Mac48Address receiver2,
+                                               Ptr<ns3::SpectrumWifiPhy> tx_phy)
+{
+    double txPower = rxPowerDbm;
+    tx_phy->SetTxPowerStart(txPower);
+    tx_phy->SetTxPowerEnd(txPower);
+
+    WifiTxVector txVector =
+        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, true);
+
+    std::vector<Ptr<WifiMpdu>> mpduList;
+
+    WifiMacHeader hdr1;
+    hdr1.SetType(WIFI_MAC_QOSDATA);
+    hdr1.SetQosTid(0);
+    hdr1.SetAddr1(receiver1); // Changing the expected receiver
+    auto p1 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p1, hdr1));
+
+    WifiMacHeader hdr2;
+    hdr2.SetType(WIFI_MAC_QOSDATA);
+    hdr2.SetQosTid(0);
+    hdr2.SetAddr1(receiver2); // Changing the expected receiver
+    auto p2 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p2, hdr2));
+
+    auto psdu = Create<WifiPsdu>(mpduList);
+
+    tx_phy->Send(psdu, txVector);
+}
+
+void
+TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu(double rxPowerDbm,
+                                              Mac48Address receiver1,
+                                              Ptr<ns3::SpectrumWifiPhy> tx_phy)
+{
+    double txPower = rxPowerDbm;
+    tx_phy->SetTxPowerStart(txPower);
+    tx_phy->SetTxPowerEnd(txPower);
+
+    WifiTxVector txVector =
+        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, true);
+
+    std::vector<Ptr<WifiMpdu>> mpduList;
+
+    WifiMacHeader hdr1;
+    hdr1.SetType(WIFI_MAC_QOSDATA);
+    hdr1.SetQosTid(0);
+    hdr1.SetAddr1(receiver1); // Changing the expected receiver
+    auto p1 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p1, hdr1));
+
+    auto psdu = Create<WifiPsdu>(mpduList);
+    tx_phy->Send(psdu, txVector);
+}
+
+void
+TestWifiPhyRxTraceHelper::CheckAllStats(uint64_t expectedPpduSuccess,
+                                        uint64_t expectedPpduFailure,
+                                        uint64_t expectedMpduSuccess,
+                                        uint64_t expectedMpduFailure,
+                                        uint64_t expectedOverlaps,
+                                        uint64_t expectedNonOverlaps)
+{
+    WifiPhyTraceStatistics stats = m_rxTraceHelper.GetStatistics();
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedPpduSuccess,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedPpduFailure,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedMpduSuccess,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedMpduFailure,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedOverlaps,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedNonOverlaps,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+    m_rxTraceHelper.Reset();
+}
+
+void
+TestWifiPhyRxTraceHelper::CheckStats(WifiPhyTraceStatistics expectedStats,
+                                     uint32_t nodeId,
+                                     uint32_t deviceId,
+                                     uint32_t linkId)
+{
+    WifiPhyTraceStatistics stats = m_rxTraceHelper.GetStatistics(nodeId, deviceId, linkId);
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedStats.m_receivedPpdus,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedStats.m_failedPpdus,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedStats.m_receivedMpdus,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedStats.m_failedMpdus,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedStats.m_overlappingPpdus,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedStats.m_nonOverlappingPpdus,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+}
+
+void
+TestWifiPhyRxTraceHelper::CheckRecords(uint64_t expectedRecordCount)
+{
+    auto records = m_rxTraceHelper.GetPpduRecords();
+    NS_TEST_ASSERT_MSG_EQ(records.size(),
+                          expectedRecordCount,
+                          "Didn't produce the right number of Records");
+}
+
+void
+TestWifiPhyRxTraceHelper::DoRun()
+{
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(2);
+    int64_t streamNumber = 1;
+    double rxPowerDbm = -80;
+    streamNumber += m_txA->AssignStreams(streamNumber);
+    streamNumber += m_txB->AssignStreams(streamNumber);
+    streamNumber += m_rx->AssignStreams(streamNumber);
+    WifiPhyTraceStatistics expectedStats;
+
+    m_rxTraceHelper.Start(Seconds(0.01));
+
+    // CASE 1: PPDU Reception with Sufficient RSSI With SOME Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 1;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 1;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.1),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.19),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        2); // Total Records
+
+    Simulator::Schedule(Seconds(0.2),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.2),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 2: PPDU Reception with inSufficient RSSI With SOME Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 1;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 1;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+    rxPowerDbm = -83;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.3),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.39),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(0.4),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.4),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 3: PPDU Reception with Sufficient RSSI/SNR With NO Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.5),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.59),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(0.6),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.6),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 4: PPDU Reception with Insufficient RSSI/SNR With NO Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -83;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.7),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.79),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(0.8),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.8),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 5: PPDU Overlapping Reception with sufficient RSSI/SNR With ALL Frames Addressed to
+    // Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 2;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 2;
+    expectedStats.m_overlappingPpdus = 2;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txB);
+
+    Simulator::Schedule(Seconds(0.99),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(Seconds(1),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 6: PPDU Overlapping Reception with sufficient RSSI/SNR With SOME Frames Addressed to
+    // Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 1;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 1;
+    expectedStats.m_overlappingPpdus = 1;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        m_txB);
+
+    Simulator::Schedule(Seconds(1.19),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.2),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.2),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // Stop Statistics Collection Period Since following testcases evaluate the Start and Stop
+    // methods
+    m_rxTraceHelper.Stop(Seconds(1.21));
+
+    // CASE 7: Execution of "Start()" Before Signal Injection
+    expectedStats.m_receivedPpdus = 1;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 1;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+    rxPowerDbm = -80;
+    m_rxTraceHelper.Start(Seconds(1.29));
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.3),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(1.39),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.4),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.4),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    m_rxTraceHelper.Stop(Seconds(1.4));
+
+    // CASE 8: Activation of "Start()" Followed by "Stop()" Before Signal Injection
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+
+    m_rxTraceHelper.Start(Seconds(1.41));
+
+    m_rxTraceHelper.Stop(Seconds(1.42));
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.45),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(1.549),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        0); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.55),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.55),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 9: "Start()" Method Initiated During Ongoing PPDU Reception
+    expectedStats.m_receivedPpdus = 1;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 1;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+    rxPowerDbm = -80;
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.6),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    m_rxTraceHelper.Start(Seconds(1.6) + MicroSeconds(10));
+
+    Simulator::Schedule(Seconds(1.69),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.7),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.7),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    m_rxTraceHelper.Stop(Seconds(1.7));
+
+    // CASE 10: Execution of "Stop()" During Ongoing PPDU Reception
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+
+    m_rxTraceHelper.Start(Seconds(1.79));
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.8),
+                        &TestWifiPhyRxTraceHelper::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    m_rxTraceHelper.Stop(Seconds(1.8) + MicroSeconds(10));
+
+    Simulator::Schedule(Seconds(1.89),
+                        &TestWifiPhyRxTraceHelper::CheckRecords,
+                        this,
+                        0); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.9),
+                        &TestWifiPhyRxTraceHelper::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.9),
+                        &TestWifiPhyRxTraceHelper::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    Simulator::Run();
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \brief Implements a test case to evaluate the reception process of WiFi Physical Layer (PHY)
+ * frames (PPDU) containing multiple MAC Protocol Data Units (MPDUs) in Multi-Link Operation (MLO)
+ * contexts.
+ *
+ * This class extends the TestCase class to simulate and analyze the reception of PPDUs containing
+ * either one or two MPDUs in MLO setups. It specifically assesses the WifiPhyRxTraceHelper
+ * ability to manage MLO by handling multiple MPDUs addressed to specific receivers across different
+ * links, measuring success and failure rates. The simulation setup includes configuring transmit
+ * and receive power levels and provides functionality to check statistics related to PPDU and MPDU
+ * reception success and failure, as well overlaps and non-overlaps in reception
+ * events.
+ */
+class TestWifiPhyRxTraceHelperMloStr : public TestCase
+{
+  public:
+    /**
+     * Constructs a TestWifiPhyRxTraceHelperMloStr instance for MLO reception testing.
+     */
+    TestWifiPhyRxTraceHelperMloStr();
+
+  private:
+    void DoSetup() override;
+    void DoRun() override;
+
+    void DoTeardown() override;
+
+    /**
+     * Sends a PPDU containing two MPDUs addressed to specific receivers, simulating an MLO
+     * scenario.
+     * \param rxPowerDbm The transmit power in dBm.
+     * \param add1 The MAC address of the first receiver.
+     * \param add2 The MAC address of the second receiver.
+     * \param tx_phy The transmitting PHY object for MLO.
+     */
+    void SendPpduWithTwoMpdus(double rxPowerDbm,
+                              Mac48Address add1,
+                              Mac48Address add2,
+                              Ptr<ns3::SpectrumWifiPhy> tx_phy);
+
+    /**
+     * Sends a PPDU containing one MPDU addressed to a specific receiver, within an MLO setup.
+     * \param rxPowerDbm The transmit power in dBm.
+     * \param add1 The MAC address of the receiver.
+     * \param tx_phy The transmitting PHY object for MLO.
+     */
+    void SendPpduWithOneMpdu(double rxPowerDbm,
+                             Mac48Address add1,
+                             Ptr<ns3::SpectrumWifiPhy> tx_phy);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedStats The expected counts for PPDU and MPDU reception.
+     * @param nodeId The node ID for which to check the received stats.
+     */
+    void CheckStats(WifiPhyTraceStatistics expectedStats, uint32_t nodeId);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedStats The expected counts for PPDU and MPDU reception.
+     * @param nodeId The node ID for which to check the received stats.
+     * @param deviceId The device ID for which to check the received stats.
+     */
+    void CheckStats(WifiPhyTraceStatistics expectedStats, uint32_t nodeId, uint32_t deviceId);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedStats The expected counts for PPDU and MPDU reception.
+     * @param nodeId The node ID for which to check the received stats.
+     * @param deviceId The device ID for which to check the received stats.
+     * @param linkId The link ID for which to check the received stats.
+     */
+    void CheckStats(WifiPhyTraceStatistics expectedStats,
+                    uint32_t nodeId,
+                    uint32_t deviceId,
+                    uint32_t linkId);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure in MLO scenarios.
+     * \param expectedPpduSuccess The expected number of successful PPDU receptions.
+     * \param expectedPpduFailure The expected number of failed PPDU receptions.
+     * \param expectedMpduSuccess The expected number of successful MPDU receptions within PPDUs.
+     * \param expectedMpduFailure The expected number of failed MPDU receptions within PPDUs.
+     * \param expectedOverlaps The expected number of overlapping reception events.
+     * \param expectedNonOverlaps The expected number of non-overlapping reception events.
+     */
+    void CheckAllStats(uint64_t expectedPpduSuccess,
+                       uint64_t expectedPpduFailure,
+                       uint64_t expectedMpduSuccess,
+                       uint64_t expectedMpduFailure,
+                       uint64_t expectedOverlaps,
+                       uint64_t expectedNonOverlaps);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedRecordCount The expected number of records.
+     */
+    void CheckRecords(uint64_t expectedRecordCount);
+
+    Mac48Address wrongReceiver =
+        Mac48Address("00:00:00:00:00:01"); ///< The MAC address representing an incorrect receiver,
+                                           ///< used for testing in MLO.
+    Mac48Address correctReceiver =
+        Mac48Address("00:00:00:00:00:03"); ///< The MAC address representing the correct receiver,
+                                           ///< used for testing in MLO.
+
+    std::map<ns3::Mac48Address, uint32_t> MacToNodeId = {
+        {Mac48Address("00:00:00:00:00:04"), 0},
+        {Mac48Address("00:00:00:00:00:05"), 1},
+        {correctReceiver, 2},
+        {wrongReceiver, 3}}; ///< Maps MAC addresses to node IDs for MLO test configuration. This is
+                             ///< done since there is no MAC layer configured and therefore the
+                             ///< helper cannot obtain the MAC addresses automatically.
+
+    NodeContainer wifiNodes;              ///< All wifi nodes
+    Ptr<SpectrumWifiPhy> m_tx0A{nullptr}; ///< The transmit function for node 0, link A.
+    Ptr<SpectrumWifiPhy> m_tx0B{nullptr}; ///< The transmit function for node 0, link B.
+    Ptr<SpectrumWifiPhy> m_tx1A{nullptr}; ///< The transmit function for node 1, link A.
+    Ptr<SpectrumWifiPhy> m_tx1B{nullptr}; ///< The transmit function for node 1, link B.
+    Ptr<SpectrumWifiPhy> m_rxA{nullptr};  ///< The receive function for node 2, link A.
+    Ptr<SpectrumWifiPhy> m_rxB{nullptr};  ///< The receive function for node 2, link B.
+
+    WifiPhyRxTraceHelper m_rxTraceHelper; ///< The helper being tested for tracking
+                                          ///< PHY reception events in MLO scenarios.
+};
+
+TestWifiPhyRxTraceHelperMloStr::TestWifiPhyRxTraceHelperMloStr()
+    : TestCase("Test for correct MLO operation")
+{
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::DoSetup()
+{
+    double txPower = 20;
+    auto ehtConfiguration = CreateObject<EhtConfiguration>();
+
+    auto nodeA = CreateObject<Node>();
+    auto devA = CreateObject<WifiNetDevice>();
+    devA->SetStandard(WIFI_STANDARD_80211be);
+    devA->SetEhtConfiguration(ehtConfiguration);
+
+    m_tx0A = CreateObject<SpectrumWifiPhy>();
+    m_tx0A->SetDevice(devA);
+    m_tx0A->SetTxPowerStart(txPower);
+    m_tx0A->SetTxPowerEnd(txPower);
+
+    m_tx0B = CreateObject<SpectrumWifiPhy>();
+    m_tx0B->SetDevice(devA);
+    m_tx0B->SetTxPowerStart(txPower);
+    m_tx0B->SetTxPowerEnd(txPower);
+
+    auto nodeB = CreateObject<Node>();
+    auto devB = CreateObject<WifiNetDevice>();
+    devB->SetStandard(WIFI_STANDARD_80211be);
+    devB->SetEhtConfiguration(ehtConfiguration);
+
+    m_tx1A = CreateObject<SpectrumWifiPhy>();
+    m_tx1A->SetDevice(devB);
+    m_tx1A->SetTxPowerStart(txPower);
+    m_tx1A->SetTxPowerEnd(txPower);
+
+    m_tx1B = CreateObject<SpectrumWifiPhy>();
+    m_tx1B->SetDevice(devB);
+    m_tx1B->SetTxPowerStart(txPower);
+    m_tx1B->SetTxPowerEnd(txPower);
+
+    auto nodeRx = CreateObject<Node>();
+    auto devRx = CreateObject<WifiNetDevice>();
+    devRx->SetStandard(WIFI_STANDARD_80211be);
+    devRx->SetEhtConfiguration(ehtConfiguration);
+    m_rxA = CreateObject<SpectrumWifiPhy>();
+    m_rxA->SetDevice(devRx);
+    m_rxB = CreateObject<SpectrumWifiPhy>();
+    m_rxB->SetDevice(devRx);
+
+    auto interferenceTx0A = CreateObject<InterferenceHelper>();
+    m_tx0A->SetInterferenceHelper(interferenceTx0A);
+    auto errorTx0A = CreateObject<NistErrorRateModel>();
+    m_tx0A->SetErrorRateModel(errorTx0A);
+
+    auto interferenceTx0B = CreateObject<InterferenceHelper>();
+    m_tx0B->SetInterferenceHelper(interferenceTx0B);
+    auto errorTx0B = CreateObject<NistErrorRateModel>();
+    m_tx0B->SetErrorRateModel(errorTx0B);
+
+    auto interferenceTx1A = CreateObject<InterferenceHelper>();
+    m_tx1A->SetInterferenceHelper(interferenceTx1A);
+    auto errorTx1A = CreateObject<NistErrorRateModel>();
+    m_tx1A->SetErrorRateModel(errorTx1A);
+
+    auto interferenceTx1B = CreateObject<InterferenceHelper>();
+    m_tx1B->SetInterferenceHelper(interferenceTx1B);
+    auto errorTx1B = CreateObject<NistErrorRateModel>();
+    m_tx1B->SetErrorRateModel(errorTx1B);
+
+    auto interferenceRxA = CreateObject<InterferenceHelper>();
+    m_rxA->SetInterferenceHelper(interferenceRxA);
+    auto errorRxA = CreateObject<NistErrorRateModel>();
+    m_rxA->SetErrorRateModel(errorRxA);
+
+    auto interferenceRxB = CreateObject<InterferenceHelper>();
+    m_rxB->SetInterferenceHelper(interferenceRxB);
+    auto errorRxB = CreateObject<NistErrorRateModel>();
+    m_rxB->SetErrorRateModel(errorRxB);
+
+    auto spectrumChannelA = CreateObject<MultiModelSpectrumChannel>();
+    auto spectrumChannelB = CreateObject<MultiModelSpectrumChannel>();
+
+    m_tx0A->SetOperatingChannel(WifiPhy::ChannelTuple{2, 0, WIFI_PHY_BAND_2_4GHZ, 0});
+    m_tx0B->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+
+    m_tx1A->SetOperatingChannel(WifiPhy::ChannelTuple{2, 0, WIFI_PHY_BAND_2_4GHZ, 0});
+    m_tx1B->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+
+    m_rxA->SetOperatingChannel(WifiPhy::ChannelTuple{2, 0, WIFI_PHY_BAND_2_4GHZ, 0});
+    m_rxB->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+
+    m_tx0A->AddChannel(spectrumChannelA, WIFI_SPECTRUM_2_4_GHZ);
+    m_tx0B->AddChannel(spectrumChannelB, WIFI_SPECTRUM_5_GHZ);
+
+    m_tx1A->AddChannel(spectrumChannelA, WIFI_SPECTRUM_2_4_GHZ);
+    m_tx1B->AddChannel(spectrumChannelB, WIFI_SPECTRUM_5_GHZ);
+
+    m_rxA->AddChannel(spectrumChannelA, WIFI_SPECTRUM_2_4_GHZ);
+    m_rxB->AddChannel(spectrumChannelB, WIFI_SPECTRUM_5_GHZ);
+
+    m_tx0A->ConfigureStandard(WIFI_STANDARD_80211be);
+    m_tx0B->ConfigureStandard(WIFI_STANDARD_80211be);
+
+    m_tx1A->ConfigureStandard(WIFI_STANDARD_80211be);
+    m_tx1B->ConfigureStandard(WIFI_STANDARD_80211be);
+
+    m_rxA->ConfigureStandard(WIFI_STANDARD_80211be);
+    m_rxB->ConfigureStandard(WIFI_STANDARD_80211be);
+
+    std::vector<Ptr<WifiPhy>> phys0;
+    phys0.emplace_back(m_tx0A);
+    phys0.emplace_back(m_tx0B);
+
+    std::vector<Ptr<WifiPhy>> phys1;
+    phys1.emplace_back(m_tx1A);
+    phys1.emplace_back(m_tx1B);
+
+    std::vector<Ptr<WifiPhy>> physRx;
+    physRx.emplace_back(m_rxA);
+    physRx.emplace_back(m_rxB);
+
+    devA->SetPhys(phys0);
+    nodeA->AddDevice(devA);
+
+    devB->SetPhys(phys1);
+    nodeB->AddDevice(devB);
+
+    devRx->SetPhys(physRx);
+    nodeRx->AddDevice(devRx);
+
+    wifiNodes.Add(nodeA);
+    wifiNodes.Add(nodeB);
+    wifiNodes.Add(nodeRx);
+
+    m_rxTraceHelper.Enable(wifiNodes, MacToNodeId);
+
+    auto preambleDetectionModel = CreateObject<ThresholdPreambleDetectionModel>();
+    preambleDetectionModel->SetAttribute("Threshold", DoubleValue(4));
+    preambleDetectionModel->SetAttribute("MinimumRssi", DoubleValue(-82));
+    m_rxA->SetPreambleDetectionModel(preambleDetectionModel);
+    m_rxB->SetPreambleDetectionModel(preambleDetectionModel);
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::DoTeardown()
+{
+    m_tx0A->Dispose();
+    m_tx0B->Dispose();
+    m_tx1A->Dispose();
+    m_tx1B->Dispose();
+    m_rxA->Dispose();
+    m_rxB->Dispose();
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus(double rxPowerDbm,
+                                                     Mac48Address receiver1,
+                                                     Mac48Address receiver2,
+                                                     Ptr<ns3::SpectrumWifiPhy> tx_phy)
+{
+    double txPower = rxPowerDbm;
+    tx_phy->SetTxPowerStart(txPower);
+    tx_phy->SetTxPowerEnd(txPower);
+
+    WifiTxVector txVector =
+        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, true);
+
+    std::vector<Ptr<WifiMpdu>> mpduList;
+
+    WifiMacHeader hdr1;
+    hdr1.SetType(WIFI_MAC_QOSDATA);
+    hdr1.SetQosTid(0);
+    hdr1.SetAddr1(receiver1); // Changing the expected receiver
+    auto p1 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p1, hdr1));
+
+    WifiMacHeader hdr2;
+    hdr2.SetType(WIFI_MAC_QOSDATA);
+    hdr2.SetQosTid(0);
+    hdr2.SetAddr1(receiver2); // Changing the expected receiver
+    auto p2 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p2, hdr2));
+
+    auto psdu = Create<WifiPsdu>(mpduList);
+
+    tx_phy->Send(psdu, txVector);
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu(double rxPowerDbm,
+                                                    Mac48Address receiver1,
+                                                    Ptr<ns3::SpectrumWifiPhy> tx_phy)
+{
+    double txPower = rxPowerDbm;
+    tx_phy->SetTxPowerStart(txPower);
+    tx_phy->SetTxPowerEnd(txPower);
+
+    WifiTxVector txVector =
+        WifiTxVector(HePhy::GetHeMcs0(),
+                     0,
+                     WIFI_PREAMBLE_HE_SU,
+                     800,
+                     1,
+                     1,
+                     0,
+                     20,
+                     true); // for some reason needs to be set to true even though only one MPDU
+
+    std::vector<Ptr<WifiMpdu>> mpduList;
+
+    WifiMacHeader hdr1;
+    hdr1.SetType(WIFI_MAC_QOSDATA);
+    hdr1.SetQosTid(0);
+    hdr1.SetAddr1(receiver1); // Changing the expected receiver
+    auto p1 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p1, hdr1));
+
+    auto psdu = Create<WifiPsdu>(mpduList);
+    tx_phy->Send(psdu, txVector);
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::CheckStats(WifiPhyTraceStatistics expectedStats, uint32_t nodeId)
+{
+    WifiPhyTraceStatistics stats;
+    for (uint32_t i = 0; i < wifiNodes.Get(nodeId)->GetNDevices(); i++)
+    {
+        for (uint32_t j = 0;
+             j < DynamicCast<WifiNetDevice>(wifiNodes.Get(nodeId)->GetDevice(i))->GetNPhys();
+             j++)
+        {
+            stats = stats + m_rxTraceHelper.GetStatistics(nodeId, i, j);
+        }
+    }
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedStats.m_receivedPpdus,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedStats.m_failedPpdus,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedStats.m_receivedMpdus,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedStats.m_failedMpdus,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedStats.m_overlappingPpdus,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedStats.m_nonOverlappingPpdus,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::CheckStats(WifiPhyTraceStatistics expectedStats,
+                                           uint32_t nodeId,
+                                           uint32_t deviceId)
+{
+    WifiPhyTraceStatistics stats;
+
+    for (uint32_t i = 0;
+         i < DynamicCast<WifiNetDevice>(wifiNodes.Get(nodeId)->GetDevice(deviceId))->GetNPhys();
+         i++)
+    {
+        stats = stats + m_rxTraceHelper.GetStatistics(nodeId, deviceId, i);
+    }
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedStats.m_receivedPpdus,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedStats.m_failedPpdus,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedStats.m_receivedMpdus,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedStats.m_failedMpdus,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedStats.m_overlappingPpdus,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedStats.m_nonOverlappingPpdus,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::CheckStats(WifiPhyTraceStatistics expectedStats,
+                                           uint32_t nodeId,
+                                           uint32_t deviceId,
+                                           uint32_t linkId)
+{
+    WifiPhyTraceStatistics stats = m_rxTraceHelper.GetStatistics(nodeId, deviceId, linkId);
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedStats.m_receivedPpdus,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedStats.m_failedPpdus,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedStats.m_receivedMpdus,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedStats.m_failedMpdus,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedStats.m_overlappingPpdus,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedStats.m_nonOverlappingPpdus,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::CheckAllStats(uint64_t expectedPpduSuccess,
+                                              uint64_t expectedPpduFailure,
+                                              uint64_t expectedMpduSuccess,
+                                              uint64_t expectedMpduFailure,
+                                              uint64_t expectedOverlaps,
+                                              uint64_t expectedNonOverlaps)
+{
+    WifiPhyTraceStatistics stats = m_rxTraceHelper.GetStatistics();
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedPpduSuccess,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedPpduFailure,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedMpduSuccess,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedMpduFailure,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedOverlaps,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedNonOverlaps,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+
+    m_rxTraceHelper.Reset();
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::CheckRecords(uint64_t expectedRecordCount)
+{
+    auto records = m_rxTraceHelper.GetPpduRecords();
+    NS_TEST_ASSERT_MSG_EQ(records.size(),
+                          expectedRecordCount,
+                          "Didn't produce the right number of Records");
+}
+
+void
+TestWifiPhyRxTraceHelperMloStr::DoRun()
+{
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(2);
+    int64_t streamNumber = 1;
+    double rxPowerDbm = -80;
+    streamNumber += m_tx0A->AssignStreams(streamNumber);
+    streamNumber += m_tx0B->AssignStreams(streamNumber);
+    streamNumber += m_tx1A->AssignStreams(streamNumber);
+    streamNumber += m_tx1B->AssignStreams(streamNumber);
+    streamNumber += m_rxA->AssignStreams(streamNumber);
+    streamNumber += m_rxB->AssignStreams(streamNumber);
+    WifiPhyTraceStatistics expectedStats;
+
+    m_rxTraceHelper.Start(Seconds(0.01));
+
+    // CASE 1: PPDU Reception with Sufficient RSSI With SOME Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 2;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 2;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 2;
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.1),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_tx0A);
+
+    Simulator::Schedule(Seconds(0.1),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_tx0B);
+
+    Simulator::Schedule(Seconds(0.19),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckRecords,
+                        this,
+                        4); // Total Records
+
+    Simulator::Schedule(
+        Seconds(0.2),
+        static_cast<void (TestWifiPhyRxTraceHelperMloStr::*)(WifiPhyTraceStatistics, uint32_t)>(
+            &TestWifiPhyRxTraceHelperMloStr::CheckStats),
+        this,
+        expectedStats,
+        wifiNodes.Get(2)->GetId());
+
+    Simulator::Schedule(Seconds(0.2),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 2: PPDU Reception with Insufficient RSSI With SOME Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 2;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 2;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 2;
+    rxPowerDbm = -83;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.3),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_tx0A);
+
+    Simulator::Schedule(Seconds(0.3),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_tx0B);
+
+    Simulator::Schedule(Seconds(0.39),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(
+        Seconds(0.4),
+        static_cast<void (TestWifiPhyRxTraceHelperMloStr::*)(WifiPhyTraceStatistics, uint32_t)>(
+            &TestWifiPhyRxTraceHelperMloStr::CheckStats),
+        this,
+        expectedStats,
+        wifiNodes.Get(2)->GetId());
+
+    Simulator::Schedule(Seconds(0.4),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 3: PPDU Reception with Sufficient RSSI/SNR With NO Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.5),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_tx0A);
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.5),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_tx0B);
+
+    Simulator::Schedule(Seconds(0.59),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(
+        Seconds(0.6),
+        static_cast<void (TestWifiPhyRxTraceHelperMloStr::*)(WifiPhyTraceStatistics, uint32_t)>(
+            &TestWifiPhyRxTraceHelperMloStr::CheckStats),
+        this,
+        expectedStats,
+        wifiNodes.Get(2)->GetId());
+
+    Simulator::Schedule(Seconds(0.6),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 4: PPDU Reception with Insufficient RSSI/SNR With NO Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -83;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.7),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_tx0A);
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.7),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_tx0B);
+
+    Simulator::Schedule(Seconds(0.79),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(
+        Seconds(0.8),
+        static_cast<void (TestWifiPhyRxTraceHelperMloStr::*)(WifiPhyTraceStatistics, uint32_t)>(
+            &TestWifiPhyRxTraceHelperMloStr::CheckStats),
+        this,
+        expectedStats,
+        wifiNodes.Get(2)->GetId());
+
+    Simulator::Schedule(Seconds(0.8),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 5: PPDU Overlapping Reception with sufficient RSSI/SNR With ALL Frames Addressed to
+    // Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 4;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 4;
+    expectedStats.m_overlappingPpdus = 4;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_tx0A);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_tx1A);
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_tx0B);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_tx1B);
+
+    Simulator::Schedule(Seconds(0.99),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckRecords,
+                        this,
+                        8); // TotalRecords
+
+    Simulator::Schedule(
+        Seconds(1),
+        static_cast<void (TestWifiPhyRxTraceHelperMloStr::*)(WifiPhyTraceStatistics, uint32_t)>(
+            &TestWifiPhyRxTraceHelperMloStr::CheckStats),
+        this,
+        expectedStats,
+        wifiNodes.Get(2)->GetId());
+
+    Simulator::Schedule(Seconds(1),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 6: PPDU Overlapping Reception with sufficient RSSI/SNR With SOME Frames Addressed to
+    // Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 2;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 2;
+    expectedStats.m_overlappingPpdus = 2;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_tx0A);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        m_tx1A);
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_tx0B);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelperMloStr::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        m_tx1B);
+
+    Simulator::Schedule(Seconds(1.19),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckRecords,
+                        this,
+                        8); // TotalRecords
+
+    Simulator::Schedule(
+        Seconds(1.2),
+        static_cast<void (TestWifiPhyRxTraceHelperMloStr::*)(WifiPhyTraceStatistics, uint32_t)>(
+            &TestWifiPhyRxTraceHelperMloStr::CheckStats),
+        this,
+        expectedStats,
+        wifiNodes.Get(2)->GetId());
+
+    Simulator::Schedule(Seconds(1.2),
+                        &TestWifiPhyRxTraceHelperMloStr::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    m_rxTraceHelper.Stop(Seconds(1.21));
+
+    Simulator::Run();
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \brief Implements a test case to evaluate the reception process of WiFi Physical Layer (PHY)
+ * frames (PPDU) with multiple MAC Protocol Data Units (MPDUs) when using YansWifiPhy.
+ *
+ * This class extends the TestCase class to simulate and analyze the reception of PPDUs containing
+ * either one or two MPDUs. It specifically tests the PHY layer's capability to handle multiple
+ * MPDUs addressed to specific receivers, measuring success and failure rates. The simulation setup
+ * includes configuring transmit and receive power levels, and the class provides functionality to
+ * check statistics related to PPDU and MPDU reception success and failure, as well as overlap
+ * handling.
+ */
+class TestWifiPhyRxTraceHelperYans : public TestCase
+{
+  public:
+    /**
+     * Constructs a TestWifiPhyRxTraceHelperYans instance for testing the trace helper with
+     * Yans.
+     */
+    TestWifiPhyRxTraceHelperYans();
+
+  private:
+    void DoSetup() override;
+    void DoRun() override;
+
+    void DoTeardown() override;
+
+    /**
+     * Sends a PPDU containing two MPDUs addressed to specific receivers.
+     * \param rxPowerDbm The transmit power in dBm.
+     * \param add1 The MAC address of the first receiver.
+     * \param add2 The MAC address of the second receiver.
+     * \param tx_phy The transmitting PHY object.
+     */
+    void SendPpduWithTwoMpdus(double rxPowerDbm,
+                              Mac48Address add1,
+                              Mac48Address add2,
+                              Ptr<ns3::YansWifiPhy> tx_phy);
+
+    /**
+     * Sends a PPDU containing one MPDU addressed to a specific receiver.
+     * \param rxPowerDbm The transmit power in dBm.
+     * \param add1 The MAC address of the receiver.
+     * \param tx_phy The transmitting PHY object.
+     */
+    void SendPpduWithOneMpdu(double rxPowerDbm, Mac48Address add1, Ptr<ns3::YansWifiPhy> tx_phy);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedPpduSuccess The expected number of successful PPDU receptions.
+     * \param expectedPpduFailure The expected number of failed PPDU receptions.
+     * \param expectedMpduSuccess The expected number of successful MPDU receptions within PPDUs.
+     * \param expectedMpduFailure The expected number of failed MPDU receptions within PPDUs.
+     * \param expectedOverlaps The expected number of overlapping reception events.
+     * \param expectedNonOverlaps The expected number of non-overlapping reception events.
+     */
+    void CheckAllStats(uint64_t expectedPpduSuccess,
+                       uint64_t expectedPpduFailure,
+                       uint64_t expectedMpduSuccess,
+                       uint64_t expectedMpduFailure,
+                       uint64_t expectedOverlaps,
+                       uint64_t expectedNonOverlaps);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedStats The expected counts for PPDU and MPDU reception.
+     * @param nodeId The node ID for which to check the received stats.
+     * @param deviceId The device ID for which to check the received stats.
+     * @param linkId The link ID for which to check the received stats.
+     */
+    void CheckStats(WifiPhyTraceStatistics expectedStats,
+                    uint32_t nodeId,
+                    uint32_t deviceId,
+                    uint32_t linkId);
+
+    /**
+     * Checks the statistics of PPDU and MPDU reception success and failure.
+     * \param expectedRecordCount The expected number of records.
+     */
+    void CheckRecords(uint64_t expectedRecordCount);
+
+    Mac48Address wrongReceiver =
+        Mac48Address("00:00:00:00:00:01"); ///< The MAC address representing an incorrect receiver,
+                                           ///< used for testing.
+    Mac48Address correctReceiver =
+        Mac48Address("00:00:00:00:00:03"); ///< The MAC address representing the correct receiver,
+                                           ///< used for testing.
+
+    std::map<ns3::Mac48Address, uint32_t> MacToNodeId = {
+        {Mac48Address("00:00:00:00:00:04"), 0},
+        {Mac48Address("00:00:00:00:00:05"), 1},
+        {correctReceiver, 2},
+        {wrongReceiver, 3}}; ///< Maps MAC addresses to node IDs. This is done since there is no MAC
+                             ///< layer configured and therefore the helper cannot obtain the MAC
+                             ///< addresses automatically.
+
+    Ptr<Node> nodeRx;                ///< The receiving node
+    Ptr<YansWifiPhy> m_txA{nullptr}; ///< The transmit function for node A.
+    Ptr<YansWifiPhy> m_txB{nullptr}; ///< The transmit function for node B.
+    Ptr<YansWifiPhy> m_rx{nullptr};  ///< The receive function for testing.
+
+    Ptr<FixedRssLossModel> propLoss; ///< The propagation loss model used to configure RSSI
+
+    WifiPhyRxTraceHelper
+        m_rxTraceHelper; ///< The helper being tested for tracking PHY reception events.
+
+    uint64_t m_uid{0}; //!< The unique identifier used for the PPDU in the test.
+};
+
+TestWifiPhyRxTraceHelperYans::TestWifiPhyRxTraceHelperYans()
+    : TestCase("Test for correct operation when using Yans")
+{
+}
+
+void
+TestWifiPhyRxTraceHelperYans::DoSetup()
+{
+    double txPower = 20;
+
+    auto yansChannel = CreateObject<YansWifiChannel>();
+    auto propDelay = CreateObject<ConstantSpeedPropagationDelayModel>();
+    propLoss = CreateObject<FixedRssLossModel>();
+    yansChannel->SetPropagationDelayModel(propDelay);
+    yansChannel->SetPropagationLossModel(propLoss);
+
+    auto nodeA = CreateObject<Node>();
+    auto devA = CreateObject<WifiNetDevice>();
+    m_txA = CreateObject<YansWifiPhy>();
+    m_txA->SetDevice(devA);
+    m_txA->SetTxPowerStart(txPower);
+    m_txA->SetTxPowerEnd(txPower);
+
+    auto nodeB = CreateObject<Node>();
+    auto devB = CreateObject<WifiNetDevice>();
+    m_txB = CreateObject<YansWifiPhy>();
+    m_txB->SetDevice(devB);
+    m_txB->SetTxPowerStart(txPower);
+    m_txB->SetTxPowerEnd(txPower);
+
+    nodeRx = CreateObject<Node>();
+    auto devRx = CreateObject<WifiNetDevice>();
+    m_rx = CreateObject<YansWifiPhy>();
+    m_rx->SetDevice(devRx);
+
+    auto interferenceTxA = CreateObject<InterferenceHelper>();
+    m_txA->SetInterferenceHelper(interferenceTxA);
+    auto errorTxA = CreateObject<NistErrorRateModel>();
+    m_txA->SetErrorRateModel(errorTxA);
+
+    auto interferenceTxB = CreateObject<InterferenceHelper>();
+    m_txB->SetInterferenceHelper(interferenceTxB);
+    auto errorTxB = CreateObject<NistErrorRateModel>();
+    m_txB->SetErrorRateModel(errorTxB);
+
+    auto interferenceRx = CreateObject<InterferenceHelper>();
+    m_rx->SetInterferenceHelper(interferenceRx);
+    auto errorRx = CreateObject<NistErrorRateModel>();
+    m_rx->SetErrorRateModel(errorRx);
+
+    m_txA->SetChannel(yansChannel);
+    m_txB->SetChannel(yansChannel);
+    m_rx->SetChannel(yansChannel);
+
+    m_txA->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_txB->ConfigureStandard(WIFI_STANDARD_80211ax);
+    m_rx->ConfigureStandard(WIFI_STANDARD_80211ax);
+
+    m_txA->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+    m_txB->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+    m_rx->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
+
+    devA->SetPhy(m_txA);
+    nodeA->AddDevice(devA);
+    devB->SetPhy(m_txB);
+    nodeB->AddDevice(devB);
+    devRx->SetPhy(m_rx);
+    nodeRx->AddDevice(devRx);
+
+    auto mobilityA = CreateObject<ConstantPositionMobilityModel>();
+    mobilityA->SetPosition(Vector(0.0, 0.0, 0.0));
+    nodeA->AggregateObject(mobilityA);
+
+    auto mobilityB = CreateObject<ConstantPositionMobilityModel>();
+    mobilityB->SetPosition(Vector(0.0, 0.0, 0.0));
+    nodeB->AggregateObject(mobilityB);
+
+    auto mobilityRx = CreateObject<ConstantPositionMobilityModel>();
+    mobilityRx->SetPosition(Vector(0.0, 0.0, 0.0));
+    nodeRx->AggregateObject(mobilityRx);
+
+    NodeContainer nodes;
+    nodes.Add(nodeA);
+    nodes.Add(nodeB);
+    nodes.Add(nodeRx);
+
+    m_rxTraceHelper.Enable(nodes, MacToNodeId);
+
+    auto preambleDetectionModel = CreateObject<ThresholdPreambleDetectionModel>();
+    preambleDetectionModel->SetAttribute("Threshold", DoubleValue(4));
+    preambleDetectionModel->SetAttribute("MinimumRssi", DoubleValue(-82));
+    m_rx->SetPreambleDetectionModel(preambleDetectionModel);
+}
+
+void
+TestWifiPhyRxTraceHelperYans::DoTeardown()
+{
+    m_txA->Dispose();
+    m_txB->Dispose();
+    m_rx->Dispose();
+}
+
+void
+TestWifiPhyRxTraceHelperYans::SendPpduWithTwoMpdus(double rxPowerDbm,
+                                                   Mac48Address receiver1,
+                                                   Mac48Address receiver2,
+                                                   Ptr<ns3::YansWifiPhy> tx_phy)
+{
+    propLoss->SetRss(rxPowerDbm);
+
+    WifiTxVector txVector =
+        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, true);
+
+    std::vector<Ptr<WifiMpdu>> mpduList;
+
+    WifiMacHeader hdr1;
+    hdr1.SetType(WIFI_MAC_QOSDATA);
+    hdr1.SetQosTid(0);
+    hdr1.SetAddr1(receiver1); // Changing the expected receiver
+    auto p1 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p1, hdr1));
+
+    WifiMacHeader hdr2;
+    hdr2.SetType(WIFI_MAC_QOSDATA);
+    hdr2.SetQosTid(0);
+    hdr2.SetAddr1(receiver2); // Changing the expected receiver
+    auto p2 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p2, hdr2));
+
+    auto psdu = Create<WifiPsdu>(mpduList);
+    auto ppdu =
+        Create<HePpdu>(psdu,
+                       txVector,
+                       tx_phy->GetOperatingChannel(),
+                       tx_phy->CalculateTxDuration(psdu->GetSize(), txVector, tx_phy->GetPhyBand()),
+                       m_uid);
+
+    m_uid++;
+
+    tx_phy->StartTx(ppdu);
+}
+
+void
+TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu(double rxPowerDbm,
+                                                  Mac48Address receiver1,
+                                                  Ptr<ns3::YansWifiPhy> tx_phy)
+{
+    propLoss->SetRss(rxPowerDbm);
+
+    auto txVector =
+        WifiTxVector(HePhy::GetHeMcs0(), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, 20, true);
+
+    std::vector<Ptr<WifiMpdu>> mpduList;
+
+    WifiMacHeader hdr1;
+    hdr1.SetType(WIFI_MAC_QOSDATA);
+    hdr1.SetQosTid(0);
+    hdr1.SetAddr1(receiver1); // Changing the expected receiver
+    auto p1 = Create<Packet>(750);
+    mpduList.emplace_back(Create<WifiMpdu>(p1, hdr1));
+
+    auto psdu = Create<WifiPsdu>(mpduList);
+    auto ppdu =
+        Create<HePpdu>(psdu,
+                       txVector,
+                       tx_phy->GetOperatingChannel(),
+                       tx_phy->CalculateTxDuration(psdu->GetSize(), txVector, tx_phy->GetPhyBand()),
+                       m_uid);
+
+    m_uid++;
+
+    tx_phy->StartTx(ppdu);
+}
+
+void
+TestWifiPhyRxTraceHelperYans::CheckAllStats(uint64_t expectedPpduSuccess,
+                                            uint64_t expectedPpduFailure,
+                                            uint64_t expectedMpduSuccess,
+                                            uint64_t expectedMpduFailure,
+                                            uint64_t expectedOverlaps,
+                                            uint64_t expectedNonOverlaps)
+{
+    auto stats = m_rxTraceHelper.GetStatistics();
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedPpduSuccess,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedPpduFailure,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedMpduSuccess,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedMpduFailure,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedOverlaps,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedNonOverlaps,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+
+    m_rxTraceHelper.Reset();
+}
+
+void
+TestWifiPhyRxTraceHelperYans::CheckStats(WifiPhyTraceStatistics expectedStats,
+                                         uint32_t nodeId,
+                                         uint32_t deviceId,
+                                         uint32_t linkId)
+{
+    WifiPhyTraceStatistics stats = m_rxTraceHelper.GetStatistics(nodeId, deviceId, linkId);
+
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedPpdus,
+                          expectedStats.m_receivedPpdus,
+                          "Didn't receive right number of successful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedPpdus,
+                          expectedStats.m_failedPpdus,
+                          "Didn't receive right number of unsuccessful PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_receivedMpdus,
+                          expectedStats.m_receivedMpdus,
+                          "Didn't receive right number of successful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_failedMpdus,
+                          expectedStats.m_failedMpdus,
+                          "Didn't receive right number of unsuccessful MPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_overlappingPpdus,
+                          expectedStats.m_overlappingPpdus,
+                          "Didn't receive right number of overlapping PPDUs");
+    NS_TEST_ASSERT_MSG_EQ(stats.m_nonOverlappingPpdus,
+                          expectedStats.m_nonOverlappingPpdus,
+                          "Didn't receive right number of nonoverlapping PPDUs");
+}
+
+void
+TestWifiPhyRxTraceHelperYans::CheckRecords(uint64_t expectedRecordCount)
+{
+    auto records = m_rxTraceHelper.GetPpduRecords();
+    NS_TEST_ASSERT_MSG_EQ(records.size(),
+                          expectedRecordCount,
+                          "Didn't produce the right number of Records");
+}
+
+void
+TestWifiPhyRxTraceHelperYans::DoRun()
+{
+    RngSeedManager::SetSeed(1);
+    RngSeedManager::SetRun(2);
+    int64_t streamNumber = 1;
+    double rxPowerDbm = -80;
+    streamNumber += m_txA->AssignStreams(streamNumber);
+    streamNumber += m_txB->AssignStreams(streamNumber);
+    streamNumber += m_rx->AssignStreams(streamNumber);
+    WifiPhyTraceStatistics expectedStats;
+
+    m_rxTraceHelper.Start(Seconds(0.01));
+
+    // CASE 1: PPDU Reception with Sufficient RSSI With SOME Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 1;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 1;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.1),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.19),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        2); // Total Records
+
+    Simulator::Schedule(Seconds(0.2),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.2),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+    // CASE 2: PPDU Reception with inSufficient RSSI With SOME Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 1;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 1;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+    rxPowerDbm = -83;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.3),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        wrongReceiver,   // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.39),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(0.4),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.4),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 3: PPDU Reception with Sufficient RSSI/SNR With NO Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.5),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.59),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(0.6),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.6),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 4: PPDU Reception with Insufficient RSSI/SNR With NO Frames Addressed to Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -83;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.7),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithTwoMpdus,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        wrongReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(0.79),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(0.8),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(0.8),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 5: PPDU Overlapping Reception with sufficient RSSI/SNR With ALL Frames Addressed to
+    // Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 2;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 2;
+    expectedStats.m_overlappingPpdus = 2;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(0.9),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txB);
+
+    Simulator::Schedule(Seconds(0.99),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(Seconds(1),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 6: PPDU Overlapping Reception with sufficient RSSI/SNR With SOME Frames Addressed to
+    // Receiver
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 1;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 1;
+    expectedStats.m_overlappingPpdus = 1;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+    // A-MPDU 2
+    Simulator::Schedule(Seconds(1.1),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        wrongReceiver, // One MPDU addressed to
+                        m_txB);
+
+    Simulator::Schedule(Seconds(1.19),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        4); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.2),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.2),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // Stop Statistics Collection Period Since following testcases evaluate the Start and Stop
+    // methods
+    m_rxTraceHelper.Stop(Seconds(1.21));
+
+    // CASE 7: Execution of "Start()" Before Signal Injection
+    expectedStats.m_receivedPpdus = 1;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 1;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+    rxPowerDbm = -80;
+    m_rxTraceHelper.Start(Seconds(1.29));
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.3),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(1.39),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.4),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.4),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    m_rxTraceHelper.Stop(Seconds(1.4));
+
+    // CASE 8: Activation of "Start()" Followed by "Stop()" Before Signal Injection
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+
+    m_rxTraceHelper.Start(Seconds(1.41));
+
+    m_rxTraceHelper.Stop(Seconds(1.42));
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.45),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    Simulator::Schedule(Seconds(1.549),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        0); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.55),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.55),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    // CASE 9: "Start()" Method Initiated During Ongoing PPDU Reception
+    expectedStats.m_receivedPpdus = 1;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 1;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 1;
+    rxPowerDbm = -80;
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.6),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    m_rxTraceHelper.Start(Seconds(1.6) + MicroSeconds(10));
+
+    Simulator::Schedule(Seconds(1.69),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        2); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.7),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.7),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    m_rxTraceHelper.Stop(Seconds(1.7));
+
+    // CASE 10: Execution of "Stop()" During Ongoing PPDU Reception
+    expectedStats.m_receivedPpdus = 0;
+    expectedStats.m_failedPpdus = 0;
+    expectedStats.m_receivedMpdus = 0;
+    expectedStats.m_failedMpdus = 0;
+    expectedStats.m_overlappingPpdus = 0;
+    expectedStats.m_nonOverlappingPpdus = 0;
+    rxPowerDbm = -80;
+
+    m_rxTraceHelper.Start(Seconds(1.79));
+
+    // A-MPDU 1
+    Simulator::Schedule(Seconds(1.8),
+                        &TestWifiPhyRxTraceHelperYans::SendPpduWithOneMpdu,
+                        this,
+                        rxPowerDbm,
+                        correctReceiver, // One MPDU addressed to
+                        m_txA);
+
+    m_rxTraceHelper.Stop(Seconds(1.8) + MicroSeconds(10));
+
+    Simulator::Schedule(Seconds(1.89),
+                        &TestWifiPhyRxTraceHelperYans::CheckRecords,
+                        this,
+                        0); // TotalRecords
+
+    Simulator::Schedule(Seconds(1.9),
+                        &TestWifiPhyRxTraceHelperYans::CheckStats,
+                        this,
+                        expectedStats,
+                        nodeRx->GetId(),
+                        0,
+                        0);
+
+    Simulator::Schedule(Seconds(1.9),
+                        &TestWifiPhyRxTraceHelperYans::CheckAllStats,
+                        this,
+                        expectedStats.m_receivedPpdus,
+                        expectedStats.m_failedPpdus,
+                        expectedStats.m_receivedMpdus,
+                        expectedStats.m_failedMpdus,
+                        expectedStats.m_overlappingPpdus,
+                        expectedStats.m_nonOverlappingPpdus);
+
+    Simulator::Run();
+    Simulator::Destroy();
+}
+
+/**
+ * \ingroup wifi-test
+ * \ingroup tests
+ *
+ * \brief wifi PHY reception Test Suite
+ */
+class WifiPhyRxTraceHelperTestSuite : public TestSuite
+{
+  public:
+    WifiPhyRxTraceHelperTestSuite();
+};
+
+WifiPhyRxTraceHelperTestSuite::WifiPhyRxTraceHelperTestSuite()
+    : TestSuite("wifi-phy-rx-trace-helper", Type::UNIT)
+{
+    AddTestCase(new TestWifiPhyRxTraceHelper("test-statistics"), TestCase::Duration::QUICK);
+    AddTestCase(new TestWifiPhyRxTraceHelperMloStr, TestCase::Duration::QUICK);
+    AddTestCase(new TestWifiPhyRxTraceHelperYans, TestCase::Duration::QUICK);
+}
+
+static WifiPhyRxTraceHelperTestSuite wifiPhyRxTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-phy-thresholds-test.cc ns-3.42/src/wifi/test/wifi-phy-thresholds-test.cc
--- ns-3.41/src/wifi/test/wifi-phy-thresholds-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-phy-thresholds-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -499,12 +499,12 @@
 };
 
 WifiPhyThresholdsTestSuite::WifiPhyThresholdsTestSuite()
-    : TestSuite("wifi-phy-thresholds", UNIT)
+    : TestSuite("wifi-phy-thresholds", Type::UNIT)
 {
-    AddTestCase(new WifiPhyThresholdsWeakWifiSignalTest, TestCase::QUICK);
-    AddTestCase(new WifiPhyThresholdsWeakForeignSignalTest, TestCase::QUICK);
-    AddTestCase(new WifiPhyThresholdsStrongWifiSignalTest, TestCase::QUICK);
-    AddTestCase(new WifiPhyThresholdsStrongForeignSignalTest, TestCase::QUICK);
+    AddTestCase(new WifiPhyThresholdsWeakWifiSignalTest, TestCase::Duration::QUICK);
+    AddTestCase(new WifiPhyThresholdsWeakForeignSignalTest, TestCase::Duration::QUICK);
+    AddTestCase(new WifiPhyThresholdsStrongWifiSignalTest, TestCase::Duration::QUICK);
+    AddTestCase(new WifiPhyThresholdsStrongForeignSignalTest, TestCase::Duration::QUICK);
 }
 
 static WifiPhyThresholdsTestSuite wifiPhyThresholdsTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-primary-channels-test.cc ns-3.42/src/wifi/test/wifi-primary-channels-test.cc
--- ns-3.41/src/wifi/test/wifi-primary-channels-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-primary-channels-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -1370,19 +1370,19 @@
 };
 
 WifiPrimaryChannelsTestSuite::WifiPrimaryChannelsTestSuite()
-    : TestSuite("wifi-primary-channels", UNIT)
+    : TestSuite("wifi-primary-channels", Type::UNIT)
 {
     // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
-    AddTestCase(new WifiPrimaryChannelsTest(40, true), TestCase::QUICK);
-    AddTestCase(new WifiPrimaryChannelsTest(40, false), TestCase::QUICK);
+    AddTestCase(new WifiPrimaryChannelsTest(40, true), TestCase::Duration::QUICK);
+    AddTestCase(new WifiPrimaryChannelsTest(40, false), TestCase::Duration::QUICK);
 #if 0
     // Tests disabled until issue #776 resolved
-    AddTestCase(new WifiPrimaryChannelsTest(80, true), TestCase::EXTENSIVE);
-    AddTestCase(new WifiPrimaryChannelsTest(80, false), TestCase::EXTENSIVE);
-    AddTestCase(new WifiPrimaryChannelsTest(160, true), TestCase::TAKES_FOREVER);
-    AddTestCase(new WifiPrimaryChannelsTest(160, false), TestCase::TAKES_FOREVER);
+    AddTestCase(new WifiPrimaryChannelsTest(80, true), TestCase::Duration::EXTENSIVE);
+    AddTestCase(new WifiPrimaryChannelsTest(80, false), TestCase::Duration::EXTENSIVE);
+    AddTestCase(new WifiPrimaryChannelsTest(160, true), TestCase::Duration::TAKES_FOREVER);
+    AddTestCase(new WifiPrimaryChannelsTest(160, false), TestCase::Duration::TAKES_FOREVER);
 #endif
-    AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::QUICK);
+    AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::Duration::QUICK);
 }
 
 static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-ru-allocation-test.cc ns-3.42/src/wifi/test/wifi-ru-allocation-test.cc
--- ns-3.41/src/wifi/test/wifi-ru-allocation-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-ru-allocation-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -688,9 +688,9 @@
 };
 
 WifiRuAllocationTestSuite::WifiRuAllocationTestSuite()
-    : TestSuite("wifi-ru-allocation", UNIT)
+    : TestSuite("wifi-ru-allocation", Type::UNIT)
 {
-    AddTestCase(new Wifi20MHzIndicesCoveringRuTest(), TestCase::QUICK);
+    AddTestCase(new Wifi20MHzIndicesCoveringRuTest(), TestCase::Duration::QUICK);
 }
 
 static WifiRuAllocationTestSuite g_wifiRuAllocationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-test.cc ns-3.42/src/wifi/test/wifi-test.cc
--- ns-3.41/src/wifi/test/wifi-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -26,7 +26,7 @@
 #include "ns3/constant-position-mobility-model.h"
 #include "ns3/error-model.h"
 #include "ns3/fcfs-wifi-queue-scheduler.h"
-#include "ns3/frame-exchange-manager.h"
+#include "ns3/he-frame-exchange-manager.h"
 #include "ns3/header-serialization-test.h"
 #include "ns3/ht-configuration.h"
 #include "ns3/interference-helper.h"
@@ -159,17 +159,21 @@
     auto manager = m_manager.Create<WifiRemoteStationManager>();
     dev->SetRemoteStationManager(manager);
 
-    Ptr<WifiMac> mac = m_mac.Create<WifiMac>();
+    auto txop = CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"));
+    m_mac.Set("Txop", PointerValue(txop));
+    auto mac = m_mac.Create<WifiMac>();
     mac->SetDevice(dev);
     mac->SetAddress(Mac48Address::Allocate());
     dev->SetMac(mac);
-    mac->ConfigureStandard(WIFI_STANDARD_80211a);
+    mac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    mac->SetFrameExchangeManagers({CreateObject<FrameExchangeManager>()});
     if (mac->GetTypeOfStation() == STA)
     {
         StaticCast<StaWifiMac>(mac)->SetAssocManager(CreateObject<WifiDefaultAssocManager>());
     }
     mac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
     Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager();
+    fem->SetAddress(mac->GetAddress());
     Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager>();
     protectionManager->SetWifiMac(mac);
     fem->SetProtectionManager(protectionManager);
@@ -352,13 +356,17 @@
     auto manager = m_manager.Create<WifiRemoteStationManager>();
     dev->SetRemoteStationManager(manager);
 
-    Ptr<WifiMac> mac = m_mac.Create<WifiMac>();
+    auto txop = CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"));
+    m_mac.Set("Txop", PointerValue(txop));
+    auto mac = m_mac.Create<WifiMac>();
     mac->SetDevice(dev);
     mac->SetAddress(Mac48Address::Allocate());
     dev->SetMac(mac);
-    mac->ConfigureStandard(WIFI_STANDARD_80211a);
+    mac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    mac->SetFrameExchangeManagers({CreateObject<FrameExchangeManager>()});
     mac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
     Ptr<FrameExchangeManager> fem = mac->GetFrameExchangeManager();
+    fem->SetAddress(mac->GetAddress());
     Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager>();
     protectionManager->SetWifiMac(mac);
     fem->SetProtectionManager(protectionManager);
@@ -570,13 +578,17 @@
     txDev->SetRemoteStationManager(m_manager.Create<WifiRemoteStationManager>());
     txNode->AddDevice(txDev);
 
+    auto txop = CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"));
+    m_mac.Set("Txop", PointerValue(txop));
     auto txMac = m_mac.Create<WifiMac>();
     txMac->SetDevice(txDev);
     txMac->SetAddress(Mac48Address::Allocate());
     txDev->SetMac(txMac);
-    txMac->ConfigureStandard(WIFI_STANDARD_80211a);
+    txMac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    txMac->SetFrameExchangeManagers({CreateObject<FrameExchangeManager>()});
     txMac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
     auto fem = txMac->GetFrameExchangeManager();
+    fem->SetAddress(txMac->GetAddress());
     auto protectionManager = CreateObject<WifiDefaultProtectionManager>();
     protectionManager->SetWifiMac(txMac);
     fem->SetProtectionManager(protectionManager);
@@ -1849,13 +1861,21 @@
     mac.SetTypeId("ns3::ApWifiMac");
     mac.Set("EnableBeaconJitter", BooleanValue(false));
     mac.Set("QosSupported", BooleanValue(true));
-    Ptr<WifiMac> apMac = mac.Create<WifiMac>();
+    for (const std::string ac : {"BE", "BK", "VI", "VO"})
+    {
+        auto qosTxop =
+            CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue(std::string("AC_") + ac));
+        mac.Set(ac + "_Txop", PointerValue(qosTxop));
+    }
+    auto apMac = mac.Create<WifiMac>();
     apMac->SetDevice(apDev);
     apMac->SetAddress(Mac48Address::Allocate());
     apDev->SetMac(apMac);
-    apMac->ConfigureStandard(WIFI_STANDARD_80211ax);
+    apMac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    apMac->SetFrameExchangeManagers({CreateObject<HeFrameExchangeManager>()});
     apMac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
     Ptr<FrameExchangeManager> fem = apMac->GetFrameExchangeManager();
+    fem->SetAddress(apMac->GetAddress());
     Ptr<WifiProtectionManager> protectionManager = CreateObject<WifiDefaultProtectionManager>();
     protectionManager->SetWifiMac(apMac);
     fem->SetProtectionManager(protectionManager);
@@ -1887,14 +1907,22 @@
     m_staPhy->SetOperatingChannel(WifiPhy::ChannelTuple{36, 20, WIFI_PHY_BAND_5GHZ, 0});
 
     mac.SetTypeId("ns3::StaWifiMac");
+    for (const std::string ac : {"BE", "BK", "VI", "VO"})
+    {
+        auto qosTxop =
+            CreateObjectWithAttributes<QosTxop>("AcIndex", StringValue(std::string("AC_") + ac));
+        mac.Set(ac + "_Txop", PointerValue(qosTxop));
+    }
     auto staMac = mac.Create<WifiMac>();
     staDev->SetMac(staMac);
     staMac->SetDevice(staDev);
     staMac->SetAddress(Mac48Address::Allocate());
-    staMac->ConfigureStandard(WIFI_STANDARD_80211ax);
+    staMac->SetChannelAccessManagers({CreateObject<ChannelAccessManager>()});
+    staMac->SetFrameExchangeManagers({CreateObject<HeFrameExchangeManager>()});
     StaticCast<StaWifiMac>(staMac)->SetAssocManager(CreateObject<WifiDefaultAssocManager>());
     staMac->SetMacQueueScheduler(CreateObject<FcfsWifiQueueScheduler>());
     fem = staMac->GetFrameExchangeManager();
+    fem->SetAddress(staMac->GetAddress());
     protectionManager = CreateObject<WifiDefaultProtectionManager>();
     protectionManager->SetWifiMac(staMac);
     fem->SetProtectionManager(protectionManager);
@@ -3791,26 +3819,26 @@
 };
 
 WifiTestSuite::WifiTestSuite()
-    : TestSuite("wifi-devices", UNIT)
+    : TestSuite("wifi-devices", Type::UNIT)
 {
-    AddTestCase(new WifiTest, TestCase::QUICK);
-    AddTestCase(new QosUtilsIsOldPacketTest, TestCase::QUICK);
-    AddTestCase(new InterferenceHelperSequenceTest, TestCase::QUICK); // Bug 991
-    AddTestCase(new DcfImmediateAccessBroadcastTestCase, TestCase::QUICK);
-    AddTestCase(new Bug730TestCase, TestCase::QUICK); // Bug 730
-    AddTestCase(new QosFragmentationTestCase, TestCase::QUICK);
-    AddTestCase(new SetChannelFrequencyTest, TestCase::QUICK);
-    AddTestCase(new Bug2222TestCase, TestCase::QUICK);            // Bug 2222
-    AddTestCase(new Bug2843TestCase, TestCase::QUICK);            // Bug 2843
-    AddTestCase(new Bug2831TestCase, TestCase::QUICK);            // Bug 2831
-    AddTestCase(new StaWifiMacScanningTestCase, TestCase::QUICK); // Bug 2399
-    AddTestCase(new Bug2470TestCase, TestCase::QUICK);            // Bug 2470
-    AddTestCase(new Issue40TestCase, TestCase::QUICK);            // Issue #40
-    AddTestCase(new Issue169TestCase, TestCase::QUICK);           // Issue #169
-    AddTestCase(new IdealRateManagerChannelWidthTest, TestCase::QUICK);
-    AddTestCase(new IdealRateManagerMimoTest, TestCase::QUICK);
-    AddTestCase(new HeRuMcsDataRateTestCase, TestCase::QUICK);
-    AddTestCase(new WifiMgtHeaderTest, TestCase::QUICK);
+    AddTestCase(new WifiTest, TestCase::Duration::QUICK);
+    AddTestCase(new QosUtilsIsOldPacketTest, TestCase::Duration::QUICK);
+    AddTestCase(new InterferenceHelperSequenceTest, TestCase::Duration::QUICK); // Bug 991
+    AddTestCase(new DcfImmediateAccessBroadcastTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new Bug730TestCase, TestCase::Duration::QUICK); // Bug 730
+    AddTestCase(new QosFragmentationTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new SetChannelFrequencyTest, TestCase::Duration::QUICK);
+    AddTestCase(new Bug2222TestCase, TestCase::Duration::QUICK);            // Bug 2222
+    AddTestCase(new Bug2843TestCase, TestCase::Duration::QUICK);            // Bug 2843
+    AddTestCase(new Bug2831TestCase, TestCase::Duration::QUICK);            // Bug 2831
+    AddTestCase(new StaWifiMacScanningTestCase, TestCase::Duration::QUICK); // Bug 2399
+    AddTestCase(new Bug2470TestCase, TestCase::Duration::QUICK);            // Bug 2470
+    AddTestCase(new Issue40TestCase, TestCase::Duration::QUICK);            // Issue #40
+    AddTestCase(new Issue169TestCase, TestCase::Duration::QUICK);           // Issue #169
+    AddTestCase(new IdealRateManagerChannelWidthTest, TestCase::Duration::QUICK);
+    AddTestCase(new IdealRateManagerMimoTest, TestCase::Duration::QUICK);
+    AddTestCase(new HeRuMcsDataRateTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new WifiMgtHeaderTest, TestCase::Duration::QUICK);
 }
 
 static WifiTestSuite g_wifiTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-transmit-mask-test.cc ns-3.42/src/wifi/test/wifi-transmit-mask-test.cc
--- ns-3.41/src/wifi/test/wifi-transmit-mask-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-transmit-mask-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -321,7 +321,7 @@
 static WifiTransmitMaskTestSuite g_WifiTransmitMaskTestSuite;
 
 WifiTransmitMaskTestSuite::WifiTransmitMaskTestSuite()
-    : TestSuite("wifi-transmit-mask", UNIT)
+    : TestSuite("wifi-transmit-mask", Type::UNIT)
 {
     // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
     // LogComponentEnable ("WifiTransmitMaskTest", logLevel);
@@ -362,7 +362,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11p 10MHz
@@ -393,7 +393,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11a
@@ -424,7 +424,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11g
@@ -437,7 +437,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11n 20MHz @ 2.4GHz
@@ -468,7 +468,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11n 20MHz @ 5GHz
@@ -499,7 +499,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11n 40MHz @ 2.4GHz
@@ -530,7 +530,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11n 20MHz @ 5GHz
@@ -561,7 +561,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ac 20MHz
@@ -592,7 +592,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ac 20MHz
@@ -623,7 +623,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ac 80MHz
@@ -654,7 +654,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ac 20MHz
@@ -685,7 +685,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 20MHz @ 2.4GHz
@@ -722,7 +722,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 20MHz @ 5GHz
@@ -759,7 +759,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 40MHz @ 2.4GHz
@@ -796,7 +796,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 40MHz @ 5GHz
@@ -833,7 +833,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 80MHz @ 2.4GHz
@@ -870,7 +870,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 80MHz @ 5GHz
@@ -907,7 +907,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 160MHz @ 2.4GHz -> not enough space so skip
@@ -955,7 +955,7 @@
                                                maskSlopes,
                                                tol,
                                                prec),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 80MHz @ 5GHz - first 20 MHz subchannel punctured
@@ -995,7 +995,7 @@
                                                tol,
                                                prec,
                                                {true, false, false, false}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 80MHz @ 5GHz - second 20 MHz subchannel punctured
@@ -1039,7 +1039,7 @@
                                                tol,
                                                prec,
                                                {false, true, false, false}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 80MHz @ 5GHz - third 20 MHz subchannel punctured
@@ -1083,7 +1083,7 @@
                                                tol,
                                                prec,
                                                {false, false, true, false}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 80MHz @ 5GHz - last 20 MHz subchannel punctured
@@ -1123,7 +1123,7 @@
                                                tol,
                                                prec,
                                                {false, false, false, true}),
-                TestCase::QUICK);
+                TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 160MHz @ 5GHz - first two 20 MHz subchannels punctured
@@ -1171,7 +1171,7 @@
                                        tol,
                                        prec,
                                        {true, true, false, false, false, false, false, false}),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 160MHz @ 5GHz - third and fourth 20 MHz subchannels punctured
@@ -1221,7 +1221,7 @@
                                        tol,
                                        prec,
                                        {false, false, true, true, false, false, false, false}),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 160MHz @ 5GHz - fifth and sixth 20 MHz subchannels punctured
@@ -1271,7 +1271,7 @@
                                        tol,
                                        prec,
                                        {false, false, false, false, true, true, false, false}),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 
     // ============================================================================================
     // 11ax 160MHz @ 5GHz - last two 20 MHz subchannels punctured
@@ -1319,5 +1319,5 @@
                                        tol,
                                        prec,
                                        {false, false, false, false, false, false, true, true}),
-        TestCase::QUICK);
+        TestCase::Duration::QUICK);
 }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wifi/test/wifi-txop-test.cc ns-3.42/src/wifi/test/wifi-txop-test.cc
--- ns-3.41/src/wifi/test/wifi-txop-test.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wifi/test/wifi-txop-test.cc	2024-05-29 15:29:47.220074000 -0700
@@ -20,7 +20,10 @@
 #include "ns3/ap-wifi-mac.h"
 #include "ns3/boolean.h"
 #include "ns3/config.h"
+#include "ns3/he-phy.h"
+#include "ns3/log.h"
 #include "ns3/mobility-helper.h"
+#include "ns3/multi-model-spectrum-channel.h"
 #include "ns3/packet-socket-client.h"
 #include "ns3/packet-socket-helper.h"
 #include "ns3/packet-socket-server.h"
@@ -29,7 +32,6 @@
 #include "ns3/qos-txop.h"
 #include "ns3/qos-utils.h"
 #include "ns3/rng-seed-manager.h"
-#include "ns3/single-model-spectrum-channel.h"
 #include "ns3/spectrum-wifi-helper.h"
 #include "ns3/string.h"
 #include "ns3/test.h"
@@ -40,23 +42,47 @@
 
 using namespace ns3;
 
+NS_LOG_COMPONENT_DEFINE("WifiTxopTest");
+
 /**
  * \ingroup wifi-test
  * \ingroup tests
  *
  * \brief Test TXOP rules
  *
- *
+ * A BSS consisting of an AP and 3 non-AP STAs is considered in this test. Both non-HT (802.11a)
+ * and HE devices are tested. Two TXOPs are simulated in this test:
+ * - In the first TXOP, the AP sends a QoS data frame to each of the three STAs. The Ack in
+ *   response to the initial frame is corrupted, hence the AP terminates the TXOP and tries again
+ *   when a new TXOP is gained. In the new TXOP, the initial frame sent to STA 1 is successfully
+ *   received, while the second frame to STA 2 is corrupted. It is checked that the AP performs
+ *   PIFS recovery or invokes backoff depending on the value of the PifsRecovery attribute. All
+ *   QoS data frames transmitted have a length/duration that does not exceed the length/duration
+ *   based RTS/CTS threshold, hence RTS/CTS is never used.
+ * - In the second TXOP, the AP sends a QoS data frame, in case of non-HT devices, or an A-MPDU
+ *   consisting of 2 MPDUs, in case of HE devices, to each of the three STAs. All PSDUs transmitted
+ *   have a length/duration that exceeds the length/duration based RTS/CTS threshold, hence RTS/CTS
+ *   is used to protect every PSDU, unless the SingleRtsPerTxop attribute is set to true, in which
+ *   case only the initial frame in the TXOP is protected by RTS/CTS.
  */
 class WifiTxopTest : public TestCase
 {
   public:
+    /// Parameters for this test
+    struct Params
+    {
+        bool nonHt;        //!< use 802.11a standard if true, 802.11ax standard otherwise
+        bool pifsRecovery; //!< whether PIFS recovery is used after failure of a non-initial frame
+        bool singleRtsPerTxop; //!< whether protection mechanism is used no more than once per TXOP
+        bool lengthBasedRtsCtsThresh; //!< if true, use length based RTS/CTS threshold; if false,
+                                      //!< use TX duration based RTS/CTS threshold
+    };
+
     /**
      * Constructor
-     * \param pifsRecovery whether PIFS recovery is used after failure of a non-initial frame
+     * \param params parameters for the Wi-Fi TXOP test
      */
-    WifiTxopTest(bool pifsRecovery);
-    ~WifiTxopTest() override;
+    WifiTxopTest(const Params& params);
 
     /**
      * Function to trace packets received by the server application
@@ -89,38 +115,63 @@
     {
         Time txStart;          ///< Frame start TX time
         Time txDuration;       ///< Frame TX duration
+        uint32_t size;         ///< PSDU size in bytes
         WifiMacHeader header;  ///< Frame MAC header
         WifiTxVector txVector; ///< TX vector used to transmit the frame
     };
 
-    uint16_t m_nStations;             ///< number of stations
-    NetDeviceContainer m_staDevices;  ///< container for stations' NetDevices
-    NetDeviceContainer m_apDevices;   ///< container for AP's NetDevice
-    std::vector<FrameInfo> m_txPsdus; ///< transmitted PSDUs
-    Time m_txopLimit;                 ///< TXOP limit
-    uint8_t m_aifsn;                  ///< AIFSN for BE
-    uint32_t m_cwMin;                 ///< CWmin for BE
-    uint16_t m_received;              ///< number of packets received by the stations
-    bool m_pifsRecovery;              ///< whether to use PIFS recovery
+    uint16_t m_nStations;                ///< number of stations
+    NetDeviceContainer m_staDevices;     ///< container for stations' NetDevices
+    NetDeviceContainer m_apDevices;      ///< container for AP's NetDevice
+    std::vector<FrameInfo> m_txPsdus;    ///< transmitted PSDUs
+    Time m_apTxopLimit;                  ///< TXOP limit for AP (AC BE)
+    uint8_t m_staAifsn;                  ///< AIFSN for STAs (AC BE)
+    uint32_t m_staCwMin;                 ///< CWmin for STAs (AC BE)
+    uint32_t m_staCwMax;                 ///< CWmax for STAs (AC BE)
+    Time m_staTxopLimit;                 ///< TXOP limit for STAs (AC BE)
+    uint16_t m_received;                 ///< number of packets received by the stations
+    bool m_nonHt;                        ///< whether to use 802.11a or 802.11ax
+    std::size_t m_payloadSizeRtsOn;      ///< size in bytes of packets protected by RTS
+    std::size_t m_payloadSizeRtsOff;     ///< size in bytes of packets not protected by RTS
+    Time m_startTime;                    ///< time when data frame exchanges start
+    WifiMode m_mode;                     ///< wifi mode used to transmit data frames
+    bool m_pifsRecovery;                 ///< whether to use PIFS recovery
+    bool m_singleRtsPerTxop;             ///< whether to use single RTS per TXOP
+    bool m_lengthBasedRtsCtsThresh;      ///< whether to use length based RTS/CTS threshold
+    Ptr<ListErrorModel> m_apErrorModel;  ///< error model to install on the AP
+    Ptr<ListErrorModel> m_staErrorModel; ///< error model to install on a STA
+    bool m_apCorrupted;  ///< whether the frame to be corrupted by the AP has been corrupted
+    bool m_staCorrupted; ///< whether the frame to be corrupted by the STA has been corrupted
 };
 
-WifiTxopTest::WifiTxopTest(bool pifsRecovery)
+WifiTxopTest::WifiTxopTest(const Params& params)
     : TestCase("Check correct operation within TXOPs"),
       m_nStations(3),
-      m_txopLimit(MicroSeconds(4768)),
+      m_apTxopLimit(MicroSeconds(4768)),
+      m_staAifsn(4),
+      m_staCwMin(63),
+      m_staCwMax(511),
+      m_staTxopLimit(MicroSeconds(3232)),
       m_received(0),
-      m_pifsRecovery(pifsRecovery)
-{
-}
-
-WifiTxopTest::~WifiTxopTest()
+      m_nonHt(params.nonHt),
+      m_payloadSizeRtsOn(m_nonHt ? 2000 : 540),
+      m_payloadSizeRtsOff(500),
+      m_startTime(MilliSeconds(m_nonHt ? 410 : 520)),
+      m_mode(m_nonHt ? OfdmPhy::GetOfdmRate12Mbps() : HePhy::GetHeMcs0()),
+      m_pifsRecovery(params.pifsRecovery),
+      m_singleRtsPerTxop(params.singleRtsPerTxop),
+      m_lengthBasedRtsCtsThresh(params.lengthBasedRtsCtsThresh),
+      m_apErrorModel(CreateObject<ListErrorModel>()),
+      m_staErrorModel(CreateObject<ListErrorModel>()),
+      m_apCorrupted(false),
+      m_staCorrupted(false)
 {
 }
 
 void
 WifiTxopTest::L7Receive(std::string context, Ptr<const Packet> p, const Address& addr)
 {
-    if (p->GetSize() >= 500)
+    if (p->GetSize() >= m_payloadSizeRtsOff)
     {
         m_received++;
     }
@@ -132,23 +183,56 @@
                        WifiTxVector txVector,
                        double txPowerW)
 {
+    bool corrupted{false};
+
+    // The AP does not correctly receive the Ack sent in response to the QoS
+    // data frame sent to the first station
+    if (const auto& hdr = psduMap.begin()->second->GetHeader(0);
+        hdr.IsAck() && !m_apCorrupted && !m_txPsdus.empty() &&
+        m_txPsdus.back().header.IsQosData() &&
+        m_txPsdus.back().header.GetAddr1() == m_staDevices.Get(0)->GetAddress())
+    {
+        corrupted = m_apCorrupted = true;
+        m_apErrorModel->SetList({psduMap.begin()->second->GetPacket()->GetUid()});
+    }
+
+    // The second station does not correctly receive the first QoS data frame sent by the AP
+    if (const auto& hdr = psduMap.begin()->second->GetHeader(0);
+        !m_txPsdus.empty() && hdr.IsQosData() &&
+        hdr.GetAddr1() == m_staDevices.Get(1)->GetAddress())
+    {
+        if (!m_staCorrupted)
+        {
+            corrupted = m_staCorrupted = true;
+        }
+        if (corrupted)
+        {
+            m_staErrorModel->SetList({psduMap.begin()->second->GetPacket()->GetUid()});
+        }
+        else
+        {
+            m_staErrorModel->SetList({});
+        }
+    }
+
     // Log all transmitted frames that are not beacon frames and have been transmitted
-    // after 400ms (so as to skip association requests/responses)
-    if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() > MilliSeconds(400))
+    // after the start time (so as to skip association requests/responses)
+    if (!psduMap.begin()->second->GetHeader(0).IsBeacon() && Simulator::Now() >= m_startTime)
     {
         m_txPsdus.push_back({Simulator::Now(),
                              WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ),
+                             psduMap[SU_STA_ID]->GetSize(),
                              psduMap[SU_STA_ID]->GetHeader(0),
                              txVector});
     }
 
     // Print all the transmitted frames if the test is executed through test-runner
-    std::cout << Simulator::Now() << " " << psduMap.begin()->second->GetHeader(0).GetTypeString()
-              << " seq " << psduMap.begin()->second->GetHeader(0).GetSequenceNumber() << " to "
-              << psduMap.begin()->second->GetAddr1() << " TX duration "
-              << WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ)
-              << " duration/ID " << psduMap.begin()->second->GetHeader(0).GetDuration()
-              << std::endl;
+    NS_LOG_INFO(psduMap.begin()->second->GetHeader(0).GetTypeString()
+                << " seq " << psduMap.begin()->second->GetHeader(0).GetSequenceNumber() << " to "
+                << psduMap.begin()->second->GetAddr1() << " TX duration "
+                << WifiPhy::CalculateTxDuration(psduMap, txVector, WIFI_PHY_BAND_5GHZ)
+                << " duration/ID " << psduMap.begin()->second->GetHeader(0).GetDuration()
+                << (corrupted ? " CORRUPTED" : "") << std::endl);
 }
 
 void
@@ -164,24 +248,37 @@
     NodeContainer wifiStaNodes;
     wifiStaNodes.Create(m_nStations);
 
-    Ptr<SingleModelSpectrumChannel> spectrumChannel = CreateObject<SingleModelSpectrumChannel>();
-    Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel>();
+    auto spectrumChannel = CreateObject<MultiModelSpectrumChannel>();
+    auto lossModel = CreateObject<FriisPropagationLossModel>();
     spectrumChannel->AddPropagationLossModel(lossModel);
-    Ptr<ConstantSpeedPropagationDelayModel> delayModel =
-        CreateObject<ConstantSpeedPropagationDelayModel>();
+    auto delayModel = CreateObject<ConstantSpeedPropagationDelayModel>();
     spectrumChannel->SetPropagationDelayModel(delayModel);
 
     SpectrumWifiPhyHelper phy;
     phy.SetChannel(spectrumChannel);
+    // use default 20 MHz channel in 5 GHz band
+    phy.Set("ChannelSettings", StringValue("{0, 20, BAND_5GHZ, 0}"));
 
     Config::SetDefault("ns3::QosFrameExchangeManager::PifsRecovery", BooleanValue(m_pifsRecovery));
-    Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold", UintegerValue(1900));
+    Config::SetDefault("ns3::WifiDefaultProtectionManager::SingleRtsPerTxop",
+                       BooleanValue(m_singleRtsPerTxop));
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsThreshold",
+                           UintegerValue(m_payloadSizeRtsOn * (m_nonHt ? 1 : 2)));
+    }
+    else
+    {
+        Config::SetDefault("ns3::WifiRemoteStationManager::RtsCtsTxDurationThresh",
+                           TimeValue(Seconds(m_payloadSizeRtsOn * (m_nonHt ? 1 : 2) * 8.0 /
+                                             m_mode.GetDataRate(20))));
+    }
 
     WifiHelper wifi;
-    wifi.SetStandard(WIFI_STANDARD_80211a);
+    wifi.SetStandard(m_nonHt ? WIFI_STANDARD_80211a : WIFI_STANDARD_80211ax);
     wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                  "DataMode",
-                                 StringValue("OfdmRate12Mbps"),
+                                 WifiModeValue(m_mode),
                                  "ControlMode",
                                  StringValue("OfdmRate6Mbps"));
 
@@ -194,15 +291,27 @@
 
     m_staDevices = wifi.Install(phy, mac, wifiStaNodes);
 
-    mac.SetType("ns3::ApWifiMac",
-                "QosSupported",
-                BooleanValue(true),
-                "Ssid",
-                SsidValue(Ssid("wifi-txop-ssid")),
-                "BeaconInterval",
-                TimeValue(MicroSeconds(102400)),
-                "EnableBeaconJitter",
-                BooleanValue(false));
+    mac.SetType(
+        "ns3::ApWifiMac",
+        "QosSupported",
+        BooleanValue(true),
+        "Ssid",
+        SsidValue(Ssid("wifi-txop-ssid")),
+        "BeaconInterval",
+        TimeValue(MicroSeconds(102400)),
+        "EnableBeaconJitter",
+        BooleanValue(false),
+        "AifsnsForSta",
+        StringValue(std::string("BE ") + std::to_string(m_staAifsn)),
+        "CwMinsForSta",
+        ApWifiMac::UintAccessParamsMapValue(
+            ApWifiMac::UintAccessParamsMap{{AC_BE, std::vector<uint64_t>{m_staCwMin}}}),
+        "CwMaxsForSta",
+        StringValue(std::string("BE ") + std::to_string(m_staCwMax)),
+        "TxopLimitsForSta",
+        StringValue(std::string("BE ") + std::to_string(m_staTxopLimit.GetMicroSeconds()) + "us"));
+
+    mac.SetEdca(AC_BE, "TxopLimits", AttributeContainerValue<TimeValue>(std::list{m_apTxopLimit}));
 
     m_apDevices = wifi.Install(phy, mac, wifiApNode);
 
@@ -237,14 +346,6 @@
     mobility.Install(wifiApNode);
     mobility.Install(wifiStaNodes);
 
-    // set the TXOP limit on BE AC
-    dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
-    PointerValue ptr;
-    dev->GetMac()->GetAttribute("BE_Txop", ptr);
-    ptr.Get<QosTxop>()->SetTxopLimit(m_txopLimit);
-    m_aifsn = ptr.Get<QosTxop>()->Txop::GetAifsn();
-    m_cwMin = ptr.Get<QosTxop>()->Txop::GetMinCw();
-
     PacketSocketHelper packetSocket;
     packetSocket.Install(wifiApNode);
     packetSocket.Install(wifiStaNodes);
@@ -257,46 +358,54 @@
         socket.SetPhysicalAddress(m_staDevices.Get(i)->GetAddress());
         socket.SetProtocol(1);
 
+        if (!m_nonHt)
+        {
+            // Send one QoS data frame to establish Block Ack agreement (packet size is such that
+            // this packet is not counted as a received packet)
+            auto client = CreateObject<PacketSocketClient>();
+            client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff - 1));
+            client->SetAttribute("MaxPackets", UintegerValue(1));
+            client->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
+            client->SetRemote(socket);
+            wifiApNode.Get(0)->AddApplication(client);
+            client->SetStartTime(m_startTime - MilliSeconds(110 - i * 25));
+            client->SetStopTime(Seconds(1.0));
+        }
+
         // Send one QoS data frame (not protected by RTS/CTS) to each station
-        Ptr<PacketSocketClient> client1 = CreateObject<PacketSocketClient>();
-        client1->SetAttribute("PacketSize", UintegerValue(500));
+        auto client1 = CreateObject<PacketSocketClient>();
+        client1->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff));
         client1->SetAttribute("MaxPackets", UintegerValue(1));
         client1->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
         client1->SetRemote(socket);
         wifiApNode.Get(0)->AddApplication(client1);
-        client1->SetStartTime(MilliSeconds(410));
+        client1->SetStartTime(m_startTime);
         client1->SetStopTime(Seconds(1.0));
 
         // Send one QoS data frame (protected by RTS/CTS) to each station
-        Ptr<PacketSocketClient> client2 = CreateObject<PacketSocketClient>();
-        client2->SetAttribute("PacketSize", UintegerValue(2000));
-        client2->SetAttribute("MaxPackets", UintegerValue(1));
-        client2->SetAttribute("Interval", TimeValue(MicroSeconds(1)));
+        auto client2 = CreateObject<PacketSocketClient>();
+        client2->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOn));
+        client2->SetAttribute("MaxPackets", UintegerValue(m_nonHt ? 1 : 2));
+        client2->SetAttribute("Interval", TimeValue(Time{0}));
         client2->SetRemote(socket);
         wifiApNode.Get(0)->AddApplication(client2);
-        client2->SetStartTime(MilliSeconds(520));
+        client2->SetStartTime(m_startTime + MilliSeconds(110));
         client2->SetStopTime(Seconds(1.0));
 
-        Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
+        auto server = CreateObject<PacketSocketServer>();
         server->SetLocal(socket);
         wifiStaNodes.Get(i)->AddApplication(server);
         server->SetStartTime(Seconds(0.0));
         server->SetStopTime(Seconds(1.0));
     }
 
-    // The AP does not correctly receive the Ack sent in response to the QoS
-    // data frame sent to the first station
-    Ptr<ReceiveListErrorModel> apPem = CreateObject<ReceiveListErrorModel>();
-    apPem->SetList({9});
+    // install the error model on the AP
     dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
-    dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(apPem);
+    dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(m_apErrorModel);
 
-    // The second station does not correctly receive the first QoS
-    // data frame sent by the AP
-    Ptr<ReceiveListErrorModel> sta2Pem = CreateObject<ReceiveListErrorModel>();
-    sta2Pem->SetList({24});
+    // install the error model on the second station
     dev = DynamicCast<WifiNetDevice>(m_staDevices.Get(1));
-    dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(sta2Pem);
+    dev->GetMac()->GetWifiPhy()->SetPostReceptionErrorModel(m_staErrorModel);
 
     // UL Traffic (the first station sends one frame to the AP)
     {
@@ -305,16 +414,30 @@
         socket.SetPhysicalAddress(m_apDevices.Get(0)->GetAddress());
         socket.SetProtocol(1);
 
-        Ptr<PacketSocketClient> client = CreateObject<PacketSocketClient>();
-        client->SetAttribute("PacketSize", UintegerValue(1500));
+        if (!m_nonHt)
+        {
+            // Send one QoS data frame to establish Block Ack agreement (packet size is such that
+            // this packet is not counted as a received packet)
+            auto client = CreateObject<PacketSocketClient>();
+            client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff - 1));
+            client->SetAttribute("MaxPackets", UintegerValue(1));
+            client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
+            client->SetRemote(socket);
+            wifiStaNodes.Get(0)->AddApplication(client);
+            client->SetStartTime(m_startTime - MilliSeconds(35));
+            client->SetStopTime(Seconds(1.0));
+        }
+
+        auto client = CreateObject<PacketSocketClient>();
+        client->SetAttribute("PacketSize", UintegerValue(m_payloadSizeRtsOff));
         client->SetAttribute("MaxPackets", UintegerValue(1));
         client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
         client->SetRemote(socket);
         wifiStaNodes.Get(0)->AddApplication(client);
-        client->SetStartTime(MilliSeconds(412));
+        client->SetStartTime(m_startTime + MilliSeconds(2));
         client->SetStopTime(Seconds(1.0));
 
-        Ptr<PacketSocketServer> server = CreateObject<PacketSocketServer>();
+        auto server = CreateObject<PacketSocketServer>();
         server->SetLocal(socket);
         wifiApNode.Get(0)->AddApplication(server);
         server->SetStartTime(Seconds(0.0));
@@ -338,13 +461,44 @@
 void
 WifiTxopTest::CheckResults()
 {
+    // check that STAs used the access parameters advertised by the AP
+    for (uint32_t i = 0; i < m_staDevices.GetN(); ++i)
+    {
+        auto staEdca = DynamicCast<WifiNetDevice>(m_staDevices.Get(i))->GetMac()->GetQosTxop(AC_BE);
+        NS_TEST_EXPECT_MSG_EQ(staEdca->GetAifsn(SINGLE_LINK_OP_ID),
+                              m_staAifsn,
+                              "Unexpected AIFSN for STA " << i);
+        NS_TEST_EXPECT_MSG_EQ(staEdca->GetMinCw(SINGLE_LINK_OP_ID),
+                              m_staCwMin,
+                              "Unexpected CWmin for STA " << i);
+        NS_TEST_EXPECT_MSG_EQ(staEdca->GetMaxCw(SINGLE_LINK_OP_ID),
+                              m_staCwMax,
+                              "Unexpected CWmax for STA " << i);
+        NS_TEST_EXPECT_MSG_EQ(staEdca->GetTxopLimit(SINGLE_LINK_OP_ID),
+                              m_staTxopLimit,
+                              "Unexpected TXOP limit for STA " << i);
+    }
+
+    const auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(0));
+
+    NS_TEST_EXPECT_MSG_EQ(apDev->GetMac()->GetQosTxop(AC_BE)->GetTxopLimit(SINGLE_LINK_OP_ID),
+                          m_apTxopLimit,
+                          "Unexpected TXOP limit for AP");
+
+    const auto aifsn = apDev->GetMac()->GetQosTxop(AC_BE)->GetAifsn(SINGLE_LINK_OP_ID);
+    const auto cwMin = apDev->GetMac()->GetQosTxop(AC_BE)->GetMinCw(SINGLE_LINK_OP_ID);
     Time tEnd;                        // TX end for a frame
     Time tStart;                      // TX start for the next frame
     Time txopStart;                   // TXOP start time
     Time tolerance = NanoSeconds(50); // due to propagation delay
-    Time sifs = DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetPhy()->GetSifs();
-    Time slot = DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetPhy()->GetSlot();
+    Time sifs = apDev->GetPhy()->GetSifs();
+    Time slot = apDev->GetPhy()->GetSlot();
     Time navEnd;
+    TypeId::AttributeInformation info;
+    WifiRemoteStationManager::GetTypeId().LookupAttributeByName("RtsCtsThreshold", &info);
+    const uint32_t rtsCtsThreshold = DynamicCast<const UintegerValue>(info.initialValue)->Get();
+    WifiRemoteStationManager::GetTypeId().LookupAttributeByName("RtsCtsTxDurationThresh", &info);
+    const Time rtsCtsTxDurationThresh = DynamicCast<const TimeValue>(info.initialValue)->Get();
 
     // lambda to round Duration/ID (in microseconds) up to the next higher integer
     auto RoundDurationId = [](Time t) {
@@ -356,92 +510,124 @@
      * fails. Also, verify that a CF-end frame is sent if enough time remains in the TXOP.
      * The destination of failed frames is put in square brackets below.
      *
-     *          |---NAV-----till end TXOP--------->|
-     *          |      |----NAV--till end TXOP---->|
-     *          |      | |---------------------------NAV---------------------------------->| | | |
-     * |--------------------------NAV---------------------------->| |      |              |      |
-     * |------------------------NAV----------------------->| |      |              |      |      |
-     * |-------------NAV--------------->| Start|      |         Start|      |      | |
-     * |----------NAV----------->| TXOP |      |         TXOP |      |      |   Ack            | |
-     * |-------NAV------->| |   |      |          |   |      |      | Timeout          |      | |
-     * |---NAV---->|
-     *      |---|  |---|-backoff->|---|  |---|  |---|   |-PIFS or->|---|  |---|  |---|  |---|
-     * |-----| |QoS|  |Ack|          |QoS|  |Ack|  |QoS|   |-backoff->|QoS|  |Ack|  |QoS|  |Ack|
-     * |CFend|
-     * ----------------------------------------------------------------------------------------------------
-     * From:  AP    STA1            AP    STA1    AP                 AP    STA2    AP    STA3    AP
-     *   To: STA1   [AP]           STA1    AP   [STA2]              STA2    AP    STA3    AP     all
+     *          |--NAV----till end TXOP-------->|
+     *          |     |---NAV--till end TXOP--->|
+     *          |     |              |-------------------------NAV------------------------------>|
+     *          |     |              |     |------------------------NAV------------------------->|
+     *          |     |              |     |     |-----------------------NAV-------------------->|
+     *          |     |              |     |     |                  |-----------NAV------------->|
+     *     Start|     |         Start|     |     |                  |     |--------NAV---------->|
+     *     TXOP |     |         TXOP |     |     |   Ack            |     |     |------NAV------>|
+     *      |   |     |          |   |     |     | Timeout          |     |     |     |---NAV--->|
+     *      |---| |---|-backoff->|---| |---| |---|   |-PIFS or->|---| |---| |---| |---| |-----|
+     *      |QoS| |Ack|          |QoS| |Ack| |QoS|   |-backoff->|QoS| |Ack| |QoS| |Ack| |CFend|
+     * --------------------------------------------------------------------------------------------
+     * From:  AP   STA1            AP   STA1   AP                 AP   STA2   AP   STA3   AP
+     *   To: STA1  [AP]           STA1   AP  [STA2]              STA2   AP   STA3   AP    all
      */
 
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus.size(), 25, "Expected 25 transmitted frames");
+    // We expect 25 frames to be transmitted if SingleRtsPerTxop is false and 22 frames (2 RTS
+    // less, 2 CTS less, 1 more CF-End)
+    NS_TEST_ASSERT_MSG_EQ(m_txPsdus.size(),
+                          (m_singleRtsPerTxop ? 22 : 25),
+                          "Unexpected number of transmitted frames");
 
-    // the first frame sent after 400ms is a QoS data frame sent by the AP to STA1
+    // the first frame sent after 400ms is a QoS data frame sent by the AP to STA1 without RTS/CTS
     txopStart = m_txPsdus[0].txStart;
 
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[0].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[0].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the first station");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[0].header.GetDuration(),
-                          RoundDurationId(m_txopLimit - m_txPsdus[0].txDuration),
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_LT(m_txPsdus[0].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected not to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_LT(
+            m_txPsdus[0].txDuration,
+            rtsCtsTxDurationThresh,
+            "PSDU duration expected not to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[0].header.GetDuration(),
+                          RoundDurationId(m_apTxopLimit - m_txPsdus[0].txDuration),
                           "Duration/ID of the first frame must cover the whole TXOP");
 
     // a Normal Ack is sent by STA1
     tEnd = m_txPsdus[0].txStart + m_txPsdus[0].txDuration;
     tStart = m_txPsdus[1].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
                           "Ack in response to the first frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[1].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[1].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].header.IsAck(), true, "Expected a Normal Ack");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[1].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
                           "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[1].header.GetDuration(),
         RoundDurationId(m_txPsdus[0].header.GetDuration() - sifs - m_txPsdus[1].txDuration),
         "Duration/ID of the Ack must be derived from that of the first frame");
 
     // the AP receives a corrupted Ack in response to the frame it sent, which is the initial
     // frame of a TXOP. Hence, the TXOP is terminated and the AP retransmits the frame after
-    // invoking the backoff
+    // waiting for EIFS - DIFS + AIFS + backoff (see section 10.3.2.3.7 of 802.11-2020)
     txopStart = m_txPsdus[2].txStart;
 
     tEnd = m_txPsdus[1].txStart + m_txPsdus[1].txDuration;
     tStart = m_txPsdus[2].txStart;
 
-    NS_TEST_ASSERT_MSG_GT_OR_EQ(
+    auto apPhy = apDev->GetPhy(SINGLE_LINK_OP_ID);
+    auto eifsNoDifs = apPhy->GetSifs() + apPhy->GetAckTxTime();
+
+    NS_TEST_EXPECT_MSG_GT_OR_EQ(
         tStart - tEnd,
-        sifs + m_aifsn * slot,
+        eifsNoDifs + sifs + aifsn * slot,
         "Less than AIFS elapsed between AckTimeout and the next TXOP start");
-    NS_TEST_ASSERT_MSG_LT_OR_EQ(
+    NS_TEST_EXPECT_MSG_LT_OR_EQ(
         tStart - tEnd,
-        sifs + m_aifsn * slot + (2 * (m_cwMin + 1) - 1) * slot,
+        eifsNoDifs + sifs + aifsn * slot + (2 * (cwMin + 1) - 1) * slot,
         "More than AIFS+BO elapsed between AckTimeout and the next TXOP start");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[2].header.IsQosData(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.IsQosData(),
                           true,
                           "Expected to retransmit a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[2].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
                           "Expected to retransmit a frame to the first station");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[2].header.GetDuration(),
-                          RoundDurationId(m_txopLimit - m_txPsdus[2].txDuration),
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_LT(m_txPsdus[2].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected not to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_LT(
+            m_txPsdus[2].txDuration,
+            rtsCtsTxDurationThresh,
+            "PSDU duration expected not to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[2].header.GetDuration(),
+                          RoundDurationId(m_apTxopLimit - m_txPsdus[2].txDuration),
                           "Duration/ID of the retransmitted frame must cover the whole TXOP");
 
     // a Normal Ack is then sent by STA1
     tEnd = m_txPsdus[2].txStart + m_txPsdus[2].txDuration;
     tStart = m_txPsdus[3].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the first frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
                           "Ack in response to the first frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[3].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[3].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].header.IsAck(), true, "Expected a Normal Ack");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[3].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
                           "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[3].header.GetDuration(),
         RoundDurationId(m_txPsdus[2].header.GetDuration() - sifs - m_txPsdus[3].txDuration),
         "Duration/ID of the Ack must be derived from that of the previous frame");
@@ -450,65 +636,94 @@
     tEnd = m_txPsdus[3].txStart + m_txPsdus[3].txDuration;
     tStart = m_txPsdus[4].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Second frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[4].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[4].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the second station");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[4].header.GetDuration(),
-        RoundDurationId(m_txopLimit - (m_txPsdus[4].txStart - txopStart) - m_txPsdus[4].txDuration),
-        "Duration/ID of the second frame does not cover the remaining TXOP");
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_LT(m_txPsdus[4].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected not to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_LT(
+            m_txPsdus[4].txDuration,
+            rtsCtsTxDurationThresh,
+            "PSDU duration expected not to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[4].header.GetDuration(),
+                          RoundDurationId(m_apTxopLimit - (m_txPsdus[4].txStart - txopStart) -
+                                          m_txPsdus[4].txDuration),
+                          "Duration/ID of the second frame does not cover the remaining TXOP");
 
     // STA2 receives a corrupted frame and hence it does not send the Ack. When the AckTimeout
     // expires, the AP performs PIFS recovery or invoke backoff, without terminating the TXOP,
     // because a non-initial frame of the TXOP failed
+    auto apStationManager = apDev->GetRemoteStationManager(SINGLE_LINK_OP_ID);
+    auto staAddress = DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress();
+    auto ackTxVector = apStationManager->GetAckTxVector(staAddress, m_txPsdus[4].txVector);
     tEnd = m_txPsdus[4].txStart + m_txPsdus[4].txDuration + sifs + slot +
-           WifiPhy::CalculatePhyPreambleAndHeaderDuration(m_txPsdus[4].txVector); // AckTimeout
+           WifiPhy::CalculatePhyPreambleAndHeaderDuration(ackTxVector); // AckTimeout
     tStart = m_txPsdus[5].txStart;
 
     if (m_pifsRecovery)
     {
-        NS_TEST_ASSERT_MSG_EQ(tEnd + sifs + slot,
+        NS_TEST_EXPECT_MSG_EQ(tEnd + sifs + slot,
                               tStart,
                               "Second frame must have been sent after a PIFS");
     }
     else
     {
-        NS_TEST_ASSERT_MSG_GT_OR_EQ(
+        NS_TEST_EXPECT_MSG_GT_OR_EQ(
             tStart - tEnd,
-            sifs + m_aifsn * slot,
+            sifs + aifsn * slot,
             "Less than AIFS elapsed between AckTimeout and the next transmission");
-        NS_TEST_ASSERT_MSG_LT_OR_EQ(
+        NS_TEST_EXPECT_MSG_LT_OR_EQ(
             tStart - tEnd,
-            sifs + m_aifsn * slot + (2 * (m_cwMin + 1) - 1) * slot,
+            sifs + aifsn * slot + (2 * (cwMin + 1) - 1) * slot,
             "More than AIFS+BO elapsed between AckTimeout and the next TXOP start");
     }
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[5].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[5].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the second station");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[5].header.GetDuration(),
-        RoundDurationId(m_txopLimit - (m_txPsdus[5].txStart - txopStart) - m_txPsdus[5].txDuration),
-        "Duration/ID of the second frame does not cover the remaining TXOP");
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_LT(m_txPsdus[5].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected not to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_LT(
+            m_txPsdus[5].txDuration,
+            rtsCtsTxDurationThresh,
+            "PSDU duration expected not to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[5].header.GetDuration(),
+                          RoundDurationId(m_apTxopLimit - (m_txPsdus[5].txStart - txopStart) -
+                                          m_txPsdus[5].txDuration),
+                          "Duration/ID of the second frame does not cover the remaining TXOP");
 
     // a Normal Ack is then sent by STA2
     tEnd = m_txPsdus[5].txStart + m_txPsdus[5].txDuration;
     tStart = m_txPsdus[6].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
                           tStart,
                           "Ack in response to the second frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
                           "Ack in response to the second frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[6].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[6].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[6].header.IsAck(), true, "Expected a Normal Ack");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[6].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
                           "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[6].header.GetDuration(),
         RoundDurationId(m_txPsdus[5].header.GetDuration() - sifs - m_txPsdus[6].txDuration),
         "Duration/ID of the Ack must be derived from that of the previous frame");
@@ -517,30 +732,43 @@
     tEnd = m_txPsdus[6].txStart + m_txPsdus[6].txDuration;
     tStart = m_txPsdus[7].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Third frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[7].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[7].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the third station");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[7].header.GetDuration(),
-        RoundDurationId(m_txopLimit - (m_txPsdus[7].txStart - txopStart) - m_txPsdus[7].txDuration),
-        "Duration/ID of the third frame does not cover the remaining TXOP");
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_LT(m_txPsdus[7].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected not to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_LT(
+            m_txPsdus[7].txDuration,
+            rtsCtsTxDurationThresh,
+            "PSDU duration expected not to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[7].header.GetDuration(),
+                          RoundDurationId(m_apTxopLimit - (m_txPsdus[7].txStart - txopStart) -
+                                          m_txPsdus[7].txDuration),
+                          "Duration/ID of the third frame does not cover the remaining TXOP");
 
     // a Normal Ack is then sent by STA3
     tEnd = m_txPsdus[7].txStart + m_txPsdus[7].txDuration;
     tStart = m_txPsdus[8].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the third frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack in response to the third frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
                           "Ack in response to the third frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[8].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[8].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[8].header.IsAck(), true, "Expected a Normal Ack");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[8].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
                           "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[8].header.GetDuration(),
         RoundDurationId(m_txPsdus[7].header.GetDuration() - sifs - m_txPsdus[8].txDuration),
         "Duration/ID of the Ack must be derived from that of the previous frame");
@@ -549,10 +777,10 @@
     tEnd = m_txPsdus[8].txStart + m_txPsdus[8].txDuration;
     tStart = m_txPsdus[9].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[9].header.IsCfEnd(), true, "Expected a CF-End frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[9].header.GetDuration(),
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[9].header.IsCfEnd(), true, "Expected a CF-End frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[9].header.GetDuration(),
                           Seconds(0),
                           "Duration/ID must be set to 0 for CF-End frames");
 
@@ -560,32 +788,45 @@
     tEnd = m_txPsdus[9].txStart + m_txPsdus[9].txDuration;
     tStart = m_txPsdus[10].txStart;
 
-    NS_TEST_ASSERT_MSG_GT_OR_EQ(tStart - tEnd,
-                                sifs + m_aifsn * slot,
+    NS_TEST_EXPECT_MSG_GT_OR_EQ(tStart - tEnd,
+                                sifs + m_staAifsn * slot,
                                 "Less than AIFS elapsed between two TXOPs");
-    NS_TEST_ASSERT_MSG_LT_OR_EQ(tStart - tEnd,
-                                sifs + m_aifsn * slot + m_cwMin * slot + tolerance,
+    NS_TEST_EXPECT_MSG_LT_OR_EQ(tStart - tEnd,
+                                sifs + m_staAifsn * slot + m_staCwMin * slot + tolerance,
                                 "More than AIFS+BO elapsed between two TXOPs");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[10].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[10].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[10].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
                           "Expected a frame sent by the first station to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_LT(m_txPsdus[10].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected not to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_LT(
+            m_txPsdus[10].txDuration,
+            rtsCtsTxDurationThresh,
+            "PSDU duration expected not to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[10].header.GetDuration(),
-        RoundDurationId(m_txopLimit - m_txPsdus[10].txDuration),
+        RoundDurationId(m_staTxopLimit - m_txPsdus[10].txDuration),
         "Duration/ID of the frame sent by the first station does not cover the remaining TXOP");
 
     // a Normal Ack is then sent by the AP
     tEnd = m_txPsdus[10].txStart + m_txPsdus[10].txDuration;
     tStart = m_txPsdus[11].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Ack sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Ack sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[11].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[11].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Ack sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Ack sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].header.IsAck(), true, "Expected a Normal Ack");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[11].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
                           "Expected a Normal Ack sent to the first station");
-    NS_TEST_ASSERT_MSG_EQ(
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[11].header.GetDuration(),
         RoundDurationId(m_txPsdus[10].header.GetDuration() - sifs - m_txPsdus[11].txDuration),
         "Duration/ID of the Ack must be derived from that of the previous frame");
@@ -594,17 +835,17 @@
     tEnd = m_txPsdus[11].txStart + m_txPsdus[11].txDuration;
     tStart = m_txPsdus[12].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[12].header.IsCfEnd(), true, "Expected a CF-End frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[12].header.GetDuration(),
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].header.IsCfEnd(), true, "Expected a CF-End frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[12].header.GetDuration(),
                           Seconds(0),
                           "Duration/ID must be set to 0 for CF-End frames");
 
     /*
      * Verify that the Duration/ID of RTS/CTS frames is set correctly, that the TXOP holder is
      * kept and allows stations to ignore NAV properly and that the CF-End Frame is not sent if
-     * not enough time remains
+     * not enough time remains. If SingleRtsPerTxop is set to true, only one RTS/CTS is sent.
      *
      *          |---------------------------------------------NAV---------------------------------->|
      *          | |-----------------------------------------NAV------------------------------->| |
@@ -627,30 +868,31 @@
 
     // the first frame is an RTS frame sent by the AP to STA1
     txopStart = m_txPsdus[13].txStart;
+    std::string ack(m_nonHt ? "Normal Ack" : "Block Ack");
 
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[13].header.IsRts(), true, "Expected an RTS frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[13].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.IsRts(), true, "Expected an RTS frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
                           "Expected an RTS frame sent by the AP to the first station");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[13].header.GetDuration(),
-                          RoundDurationId(m_txopLimit - m_txPsdus[13].txDuration),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[13].header.GetDuration(),
+                          RoundDurationId(m_apTxopLimit - m_txPsdus[13].txDuration),
                           "Duration/ID of the first RTS frame must cover the whole TXOP");
 
     // a CTS is sent by STA1
     tEnd = m_txPsdus[13].txStart + m_txPsdus[13].txDuration;
     tStart = m_txPsdus[14].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
                           tStart,
                           "CTS in response to the first RTS frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
                           "CTS in response to the first RTS frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[14].header.IsCts(), true, "Expected a CTS");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[14].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].header.IsCts(), true, "Expected a CTS");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[14].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
                           "Expected a CTS frame sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[14].header.GetDuration(),
         RoundDurationId(m_txPsdus[13].header.GetDuration() - sifs - m_txPsdus[14].txDuration),
         "Duration/ID of the CTS frame must be derived from that of the RTS frame");
@@ -659,180 +901,262 @@
     tEnd = m_txPsdus[14].txStart + m_txPsdus[14].txDuration;
     tStart = m_txPsdus[15].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "First QoS data frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "First QoS data frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[15].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[15].header.GetAddr1(),
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "First QoS data frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "First QoS data frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[15].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[15].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(0))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the first station");
-    NS_TEST_ASSERT_MSG_EQ(
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_GT(m_txPsdus[15].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_GT(m_txPsdus[15].txDuration,
+                              rtsCtsTxDurationThresh,
+                              "PSDU duration expected to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[15].header.GetDuration(),
-        RoundDurationId(m_txopLimit - (m_txPsdus[15].txStart - txopStart) -
+        RoundDurationId(m_apTxopLimit - (m_txPsdus[15].txStart - txopStart) -
                         m_txPsdus[15].txDuration),
         "Duration/ID of the first QoS data frame does not cover the remaining TXOP");
 
-    // a Normal Ack is then sent by STA1
+    // a Normal/Block Ack is then sent by STA1
     tEnd = m_txPsdus[15].txStart + m_txPsdus[15].txDuration;
     tStart = m_txPsdus[16].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
                           tStart,
-                          "Ack in response to the first QoS data frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+                          ack << " in response to the first QoS data frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
-                          "Ack in response to the first QoS data frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[16].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[16].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
-                          "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
+                          ack << " in response to the first QoS data frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(
+        (m_nonHt ? m_txPsdus[16].header.IsAck() : m_txPsdus[16].header.IsBlockAck()),
+        true,
+        "Expected a " << ack);
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[16].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
+                          "Expected a " << ack << " sent to the AP");
+    NS_TEST_EXPECT_MSG_EQ(
         m_txPsdus[16].header.GetDuration(),
         RoundDurationId(m_txPsdus[15].header.GetDuration() - sifs - m_txPsdus[16].txDuration),
-        "Duration/ID of the Ack must be derived from that of the previous frame");
+        "Duration/ID of the " << ack << " must be derived from that of the previous frame");
 
-    // An RTS frame is sent by the AP to STA2
-    tEnd = m_txPsdus[16].txStart + m_txPsdus[16].txDuration;
-    tStart = m_txPsdus[17].txStart;
-
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Second RTS frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second RTS frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[17].header.IsRts(), true, "Expected an RTS frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[17].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
-                          "Expected an RTS frame sent by the AP to the second station");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[17].header.GetDuration(),
-                          RoundDurationId(m_txopLimit - (m_txPsdus[17].txStart - txopStart) -
-                                          m_txPsdus[17].txDuration),
-                          "Duration/ID of the second RTS frame must cover the whole TXOP");
-
-    // a CTS is sent by STA2 (which ignores the NAV)
-    tEnd = m_txPsdus[17].txStart + m_txPsdus[17].txDuration;
-    tStart = m_txPsdus[18].txStart;
+    std::size_t idx = 16;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
-                          tStart,
-                          "CTS in response to the second RTS frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
-                          tEnd + sifs + tolerance,
-                          "CTS in response to the second RTS frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[18].header.IsCts(), true, "Expected a CTS");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[18].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
-                          "Expected a CTS frame sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[18].header.GetDuration(),
-        RoundDurationId(m_txPsdus[17].header.GetDuration() - sifs - m_txPsdus[18].txDuration),
-        "Duration/ID of the CTS frame must be derived from that of the RTS frame");
+    if (!m_singleRtsPerTxop)
+    {
+        // An RTS frame is sent by the AP to STA2
+        tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+        ++idx;
+        tStart = m_txPsdus[idx].txStart;
+
+        NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second RTS frame sent too early");
+        NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second RTS frame sent too late");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsRts(), true, "Expected an RTS frame");
+        NS_TEST_EXPECT_MSG_EQ(
+            m_txPsdus[idx].header.GetAddr1(),
+            DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
+            "Expected an RTS frame sent by the AP to the second station");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
+                              RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
+                                              m_txPsdus[idx].txDuration),
+                              "Duration/ID of the second RTS frame must cover the whole TXOP");
+
+        // a CTS is sent by STA2 (which ignores the NAV)
+        tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+        tStart = m_txPsdus[idx + 1].txStart;
 
-    // the AP sends a frame to STA2
-    tEnd = m_txPsdus[18].txStart + m_txPsdus[18].txDuration;
-    tStart = m_txPsdus[19].txStart;
+        NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
+                              tStart,
+                              "CTS in response to the second RTS frame sent too early");
+        NS_TEST_EXPECT_MSG_LT(tStart,
+                              tEnd + sifs + tolerance,
+                              "CTS in response to the second RTS frame sent too late");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.IsCts(), true, "Expected a CTS");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
+                              apDev->GetMac()->GetAddress(),
+                              "Expected a CTS frame sent to the AP");
+        NS_TEST_EXPECT_MSG_EQ(
+            m_txPsdus[idx + 1].header.GetDuration(),
+            RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs -
+                            m_txPsdus[idx + 1].txDuration),
+            "Duration/ID of the CTS frame must be derived from that of the RTS frame");
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Second QoS data frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second QoS data frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[19].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[19].header.GetAddr1(),
+        ++idx;
+    }
+
+    // the AP sends a frame to STA2
+    tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+    ++idx;
+    tStart = m_txPsdus[idx].txStart;
+
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Second QoS data frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Second QoS data frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(1))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the second station");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[19].header.GetDuration(),
-        RoundDurationId(m_txopLimit - (m_txPsdus[19].txStart - txopStart) -
-                        m_txPsdus[19].txDuration),
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].txDuration,
+                              rtsCtsTxDurationThresh,
+                              "PSDU duration expected to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(
+        m_txPsdus[idx].header.GetDuration(),
+        RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
+                        m_txPsdus[idx].txDuration),
         "Duration/ID of the second QoS data frame does not cover the remaining TXOP");
 
-    // a Normal Ack is then sent by STA2
-    tEnd = m_txPsdus[19].txStart + m_txPsdus[19].txDuration;
-    tStart = m_txPsdus[20].txStart;
+    // a Normal/Block Ack is then sent by STA2
+    tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+    tStart = m_txPsdus[idx + 1].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
                           tStart,
-                          "Ack in response to the second QoS data frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+                          ack << " in response to the second QoS data frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
-                          "Ack in response to the second QoS data frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[20].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[20].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
-                          "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[20].header.GetDuration(),
-        RoundDurationId(m_txPsdus[19].header.GetDuration() - sifs - m_txPsdus[20].txDuration),
-        "Duration/ID of the Ack must be derived from that of the previous frame");
+                          ack << " in response to the second QoS data frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(
+        (m_nonHt ? m_txPsdus[idx + 1].header.IsAck() : m_txPsdus[idx + 1].header.IsBlockAck()),
+        true,
+        "Expected a " << ack);
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
+                          "Expected a " << ack << " sent to the AP");
+    NS_TEST_EXPECT_MSG_EQ(
+        m_txPsdus[idx + 1].header.GetDuration(),
+        RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs - m_txPsdus[idx + 1].txDuration),
+        "Duration/ID of the " << ack << " must be derived from that of the previous frame");
+    ++idx;
 
-    // An RTS frame is sent by the AP to STA3
-    tEnd = m_txPsdus[20].txStart + m_txPsdus[20].txDuration;
-    tStart = m_txPsdus[21].txStart;
-
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Third RTS frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third RTS frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[21].header.IsRts(), true, "Expected an RTS frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[21].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
-                          "Expected an RTS frame sent by the AP to the third station");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[21].header.GetDuration(),
-                          RoundDurationId(m_txopLimit - (m_txPsdus[21].txStart - txopStart) -
-                                          m_txPsdus[21].txDuration),
-                          "Duration/ID of the third RTS frame must cover the whole TXOP");
-
-    // a CTS is sent by STA3 (which ignores the NAV)
-    tEnd = m_txPsdus[21].txStart + m_txPsdus[21].txDuration;
-    tStart = m_txPsdus[22].txStart;
+    if (!m_singleRtsPerTxop)
+    {
+        // An RTS frame is sent by the AP to STA3
+        tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+        ++idx;
+        tStart = m_txPsdus[idx].txStart;
+
+        NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third RTS frame sent too early");
+        NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third RTS frame sent too late");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsRts(), true, "Expected an RTS frame");
+        NS_TEST_EXPECT_MSG_EQ(
+            m_txPsdus[idx].header.GetAddr1(),
+            DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
+            "Expected an RTS frame sent by the AP to the third station");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
+                              RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
+                                              m_txPsdus[idx].txDuration),
+                              "Duration/ID of the third RTS frame must cover the whole TXOP");
+
+        // a CTS is sent by STA3 (which ignores the NAV)
+        tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+        tStart = m_txPsdus[idx + 1].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
-                          tStart,
-                          "CTS in response to the third RTS frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
-                          tEnd + sifs + tolerance,
-                          "CTS in response to the third RTS frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[22].header.IsCts(), true, "Expected a CTS");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[22].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
-                          "Expected a CTS frame sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[22].header.GetDuration(),
-        RoundDurationId(m_txPsdus[21].header.GetDuration() - sifs - m_txPsdus[22].txDuration),
-        "Duration/ID of the CTS frame must be derived from that of the RTS frame");
+        NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
+                              tStart,
+                              "CTS in response to the third RTS frame sent too early");
+        NS_TEST_EXPECT_MSG_LT(tStart,
+                              tEnd + sifs + tolerance,
+                              "CTS in response to the third RTS frame sent too late");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.IsCts(), true, "Expected a CTS");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
+                              apDev->GetMac()->GetAddress(),
+                              "Expected a CTS frame sent to the AP");
+        NS_TEST_EXPECT_MSG_EQ(
+            m_txPsdus[idx + 1].header.GetDuration(),
+            RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs -
+                            m_txPsdus[idx + 1].txDuration),
+            "Duration/ID of the CTS frame must be derived from that of the RTS frame");
+        ++idx;
+    }
 
     // the AP sends a frame to STA3
-    tEnd = m_txPsdus[22].txStart + m_txPsdus[22].txDuration;
-    tStart = m_txPsdus[23].txStart;
-
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs, tStart, "Third QoS data frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third QoS data frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[23].header.IsQosData(), true, "Expected a QoS data frame");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[23].header.GetAddr1(),
+    tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+    ++idx;
+    tStart = m_txPsdus[idx].txStart;
+
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "Third QoS data frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "Third QoS data frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsQosData(), true, "Expected a QoS data frame");
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetAddr1(),
                           DynamicCast<WifiNetDevice>(m_staDevices.Get(2))->GetMac()->GetAddress(),
                           "Expected a frame sent by the AP to the third station");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[23].header.GetDuration(),
-        RoundDurationId(m_txopLimit - (m_txPsdus[23].txStart - txopStart) -
-                        m_txPsdus[23].txDuration),
+    if (m_lengthBasedRtsCtsThresh)
+    {
+        NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].size,
+                              rtsCtsThreshold,
+                              "PSDU size expected to exceed length based RTS/CTS threshold");
+    }
+    else
+    {
+        NS_TEST_EXPECT_MSG_GT(m_txPsdus[idx].txDuration,
+                              rtsCtsTxDurationThresh,
+                              "PSDU duration expected to exceed duration based RTS/CTS threshold");
+    }
+    NS_TEST_EXPECT_MSG_EQ(
+        m_txPsdus[idx].header.GetDuration(),
+        RoundDurationId(m_apTxopLimit - (m_txPsdus[idx].txStart - txopStart) -
+                        m_txPsdus[idx].txDuration),
         "Duration/ID of the third QoS data frame does not cover the remaining TXOP");
 
-    // a Normal Ack is then sent by STA3
-    tEnd = m_txPsdus[23].txStart + m_txPsdus[23].txDuration;
-    tStart = m_txPsdus[24].txStart;
+    // a Normal/Block Ack is then sent by STA3
+    tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+    tStart = m_txPsdus[idx + 1].txStart;
 
-    NS_TEST_ASSERT_MSG_LT(tEnd + sifs,
+    NS_TEST_EXPECT_MSG_LT(tEnd + sifs,
                           tStart,
-                          "Ack in response to the third QoS data frame sent too early");
-    NS_TEST_ASSERT_MSG_LT(tStart,
+                          ack << " in response to the third QoS data frame sent too early");
+    NS_TEST_EXPECT_MSG_LT(tStart,
                           tEnd + sifs + tolerance,
-                          "Ack in response to the third QoS data frame sent too late");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[24].header.IsAck(), true, "Expected a Normal Ack");
-    NS_TEST_ASSERT_MSG_EQ(m_txPsdus[24].header.GetAddr1(),
-                          DynamicCast<WifiNetDevice>(m_apDevices.Get(0))->GetMac()->GetAddress(),
-                          "Expected a Normal Ack sent to the AP");
-    NS_TEST_ASSERT_MSG_EQ(
-        m_txPsdus[24].header.GetDuration(),
-        RoundDurationId(m_txPsdus[23].header.GetDuration() - sifs - m_txPsdus[24].txDuration),
-        "Duration/ID of the Ack must be derived from that of the previous frame");
-
-    // there is no time remaining for sending a CF-End frame. This is verified by checking
-    // that 25 frames are transmitted (done at the beginning of this method)
+                          ack << " in response to the third QoS data frame sent too late");
+    NS_TEST_EXPECT_MSG_EQ(
+        (m_nonHt ? m_txPsdus[idx + 1].header.IsAck() : m_txPsdus[idx + 1].header.IsBlockAck()),
+        true,
+        "Expected a " << ack);
+    NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx + 1].header.GetAddr1(),
+                          apDev->GetMac()->GetAddress(),
+                          "Expected a " << ack << " sent to the AP");
+    NS_TEST_EXPECT_MSG_EQ(
+        m_txPsdus[idx + 1].header.GetDuration(),
+        RoundDurationId(m_txPsdus[idx].header.GetDuration() - sifs - m_txPsdus[idx + 1].txDuration),
+        "Duration/ID of the " << ack << " must be derived from that of the previous frame");
+    ++idx;
+
+    // there is no time remaining for sending a CF-End frame if SingleRtsPerTxop is false. This is
+    // verified by checking that 25 frames are transmitted (done at the beginning of this method)
+    if (m_singleRtsPerTxop)
+    {
+        tEnd = m_txPsdus[idx].txStart + m_txPsdus[idx].txDuration;
+        ++idx;
+        tStart = m_txPsdus[idx].txStart;
+
+        NS_TEST_EXPECT_MSG_LT(tEnd + sifs, tStart, "CF-End sent too early");
+        NS_TEST_EXPECT_MSG_LT(tStart, tEnd + sifs + tolerance, "CF-End sent too late");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.IsCfEnd(), true, "Expected a CF-End frame");
+        NS_TEST_EXPECT_MSG_EQ(m_txPsdus[idx].header.GetDuration(),
+                              Seconds(0),
+                              "Duration/ID must be set to 0 for CF-End frames");
+    }
 
-    // 3 DL packets (without RTS/CTS), 1 UL packet and 3 DL packets (with RTS/CTS)
-    NS_TEST_ASSERT_MSG_EQ(m_received, 7, "Unexpected number of packets received");
+    // Expected received packets:
+    // - 3 DL packets (without RTS/CTS)
+    // - 1 UL packet
+    // - 3 DL packets (with RTS/CTS) if non-HT, 6 DL packets (with RTS/CTS) if HE
+    NS_TEST_EXPECT_MSG_EQ(m_received, (m_nonHt ? 7 : 10), "Unexpected number of packets received");
 }
 
 /**
@@ -848,10 +1172,26 @@
 };
 
 WifiTxopTestSuite::WifiTxopTestSuite()
-    : TestSuite("wifi-txop", UNIT)
+    : TestSuite("wifi-txop", Type::UNIT)
 {
-    AddTestCase(new WifiTxopTest(true), TestCase::QUICK);
-    AddTestCase(new WifiTxopTest(false), TestCase::QUICK);
+    for (const auto nonHt : {true, false})
+    {
+        AddTestCase(new WifiTxopTest({.nonHt = nonHt,
+                                      .pifsRecovery = true,
+                                      .singleRtsPerTxop = false,
+                                      .lengthBasedRtsCtsThresh = false}),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new WifiTxopTest({.nonHt = nonHt,
+                                      .pifsRecovery = false,
+                                      .singleRtsPerTxop = true,
+                                      .lengthBasedRtsCtsThresh = false}),
+                    TestCase::Duration::QUICK);
+        AddTestCase(new WifiTxopTest({.nonHt = nonHt,
+                                      .pifsRecovery = true,
+                                      .singleRtsPerTxop = true,
+                                      .lengthBasedRtsCtsThresh = true}),
+                    TestCase::Duration::QUICK);
+    }
 }
 
 static WifiTxopTestSuite g_wifiTxopTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/helper/wimax-helper.cc ns-3.42/src/wimax/helper/wimax-helper.cc
--- ns-3.41/src/wimax/helper/wimax-helper.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wimax/helper/wimax-helper.cc	2024-05-29 15:29:47.220074000 -0700
@@ -442,14 +442,14 @@
 
 ServiceFlow
 WimaxHelper::CreateServiceFlow(ServiceFlow::Direction direction,
-                               ServiceFlow::SchedulingType schedulinType,
+                               ServiceFlow::SchedulingType schedulingType,
                                IpcsClassifierRecord classifier)
 {
     CsParameters csParam(CsParameters::ADD, classifier);
     ServiceFlow serviceFlow = ServiceFlow(direction);
     serviceFlow.SetConvergenceSublayerParam(csParam);
     serviceFlow.SetCsSpecification(ServiceFlow::IPV4);
-    serviceFlow.SetServiceSchedulingType(schedulinType);
+    serviceFlow.SetServiceSchedulingType(schedulingType);
     serviceFlow.SetMaxSustainedTrafficRate(100);
     serviceFlow.SetMinReservedTrafficRate(1000000);
     serviceFlow.SetMinTolerableTrafficRate(1000000);
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/helper/wimax-helper.h ns-3.42/src/wimax/helper/wimax-helper.h
--- ns-3.41/src/wimax/helper/wimax-helper.h	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wimax/helper/wimax-helper.h	2024-05-29 15:29:47.220074000 -0700
@@ -245,13 +245,13 @@
     /**
      * \brief Creates a transport service flow.
      * \param direction the direction of the service flow: UP or DOWN.
-     * \param schedulinType The service scheduling type to be used: UGS, RTPS, NRTPS, BE
+     * \param schedulingType The service scheduling type to be used: UGS, RTPS, NRTPS, BE
      * \param classifier The classifier to be used for this service flow
      * \return ServiceFlow
      *
      */
     ServiceFlow CreateServiceFlow(ServiceFlow::Direction direction,
-                                  ServiceFlow::SchedulingType schedulinType,
+                                  ServiceFlow::SchedulingType schedulingType,
                                   IpcsClassifierRecord classifier);
 
     /**
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/bandwidth-manager.cc ns-3.42/src/wimax/model/bandwidth-manager.cc
--- ns-3.41/src/wimax/model/bandwidth-manager.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wimax/model/bandwidth-manager.cc	2024-05-29 15:29:47.220074000 -0700
@@ -98,13 +98,9 @@
         }
     }
     break;
-    case ServiceFlow::SF_TYPE_NRTPS: {
+    case ServiceFlow::SF_TYPE_NRTPS:
         /* nrtPS shall be serviced only if sufficient bandwidth is available after servicing
          UGS and rtPS scheduling types, hence no specific service interval is used */
-
-        allocationSize = bs->GetBwReqOppSize();
-    }
-    break;
     case ServiceFlow::SF_TYPE_BE: {
         /* BE shall be serviced only if sufficient bandwidth is available after servicing
          the rest of three scheduling types, hence no specific service interval is used */
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/bs-net-device.cc ns-3.42/src/wimax/model/bs-net-device.cc
--- ns-3.41/src/wimax/model/bs-net-device.cc	2024-02-09 14:44:08.617795200 -0800
+++ ns-3.42/src/wimax/model/bs-net-device.cc	2024-05-29 15:29:47.224074000 -0700
@@ -790,7 +790,6 @@
             {
             case ManagementMessageType::MESSAGE_TYPE_REG_REQ:
                 // not yet implemented
-                break;
             case ManagementMessageType::MESSAGE_TYPE_REG_RSP:
                 // from other base station, ignore
                 break;
@@ -831,7 +830,7 @@
                 C_Packet->RemoveHeader(llc);
                 source = m_ssManager->GetMacAddress(cid);
                 m_bsRxTrace(packet);
-                ForwardUp(packet->Copy(), source, Mac48Address("ff:ff:ff:ff:ff:ff"));
+                ForwardUp(packet->Copy(), source, Mac48Address::GetBroadcast());
             }
             else
             {
@@ -861,7 +860,7 @@
                     NS_LOG_INFO("\t fullPacket size = " << fullPacket->GetSize() << std::endl);
                     source = m_ssManager->GetMacAddress(cid);
                     m_bsRxTrace(fullPacket);
-                    ForwardUp(fullPacket->Copy(), source, Mac48Address("ff:ff:ff:ff:ff:ff"));
+                    ForwardUp(fullPacket->Copy(), source, Mac48Address::GetBroadcast());
                 }
                 else
                 {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/bs-service-flow-manager.cc ns-3.42/src/wimax/model/bs-service-flow-manager.cc
--- ns-3.41/src/wimax/model/bs-service-flow-manager.cc	2024-02-09 14:44:08.621795200 -0800
+++ ns-3.42/src/wimax/model/bs-service-flow-manager.cc	2024-05-29 15:29:47.224074000 -0700
@@ -169,7 +169,7 @@
     ssRecord->IncrementDsaRspRetries();
     p->AddHeader(ManagementMessageType(ManagementMessageType::MESSAGE_TYPE_DSA_RSP));
 
-    if (m_dsaAckTimeoutEvent.IsRunning())
+    if (m_dsaAckTimeoutEvent.IsPending())
     {
         Simulator::Cancel(m_dsaAckTimeoutEvent);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/bs-uplink-scheduler-mbqos.cc ns-3.42/src/wimax/model/bs-uplink-scheduler-mbqos.cc
--- ns-3.41/src/wimax/model/bs-uplink-scheduler-mbqos.cc	2024-02-09 14:44:08.621795200 -0800
+++ ns-3.42/src/wimax/model/bs-uplink-scheduler-mbqos.cc	2024-05-29 15:29:47.224074000 -0700
@@ -1178,14 +1178,10 @@
     switch (serviceFlow->GetSchedulingType())
     {
     case ServiceFlow::SF_TYPE_RTPS:
-        EnqueueJob(UlJob::INTERMEDIATE, job);
-        break;
     case ServiceFlow::SF_TYPE_NRTPS:
         EnqueueJob(UlJob::INTERMEDIATE, job);
         break;
     case ServiceFlow::SF_TYPE_BE:
-        EnqueueJob(UlJob::LOW, job);
-        break;
     default:
         EnqueueJob(UlJob::LOW, job);
         break;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/bs-uplink-scheduler-rtps.cc ns-3.42/src/wimax/model/bs-uplink-scheduler-rtps.cc
--- ns-3.41/src/wimax/model/bs-uplink-scheduler-rtps.cc	2024-02-09 14:44:08.621795200 -0800
+++ ns-3.42/src/wimax/model/bs-uplink-scheduler-rtps.cc	2024-05-29 15:29:47.224074000 -0700
@@ -720,14 +720,11 @@
         serviceFlow->SetUnsolicitedPollingInterval(interval);
     }
     break;
-    case ServiceFlow::SF_TYPE_NRTPS: {
+    case ServiceFlow::SF_TYPE_NRTPS:
         // no real-time guarantees are given to NRTPS, serviced based on available bandwidth
-    }
-    break;
-    case ServiceFlow::SF_TYPE_BE: {
+    case ServiceFlow::SF_TYPE_BE:
         // no real-time guarantees are given to BE, serviced based on available bandwidth
-    }
-    break;
+        break;
     default:
         NS_FATAL_ERROR("Invalid scheduling type");
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/bs-uplink-scheduler-simple.cc ns-3.42/src/wimax/model/bs-uplink-scheduler-simple.cc
--- ns-3.41/src/wimax/model/bs-uplink-scheduler-simple.cc	2024-02-09 14:44:08.621795200 -0800
+++ ns-3.42/src/wimax/model/bs-uplink-scheduler-simple.cc	2024-05-29 15:29:47.224074000 -0700
@@ -569,14 +569,11 @@
         serviceFlow->SetUnsolicitedPollingInterval(interval);
     }
     break;
-    case ServiceFlow::SF_TYPE_NRTPS: {
+    case ServiceFlow::SF_TYPE_NRTPS:
         // no real-time guarantees are given to NRTPS, serviced based on available bandwidth
-    }
-    break;
-    case ServiceFlow::SF_TYPE_BE: {
+    case ServiceFlow::SF_TYPE_BE:
         // no real-time guarantees are given to BE, serviced based on available bandwidth
-    }
-    break;
+        break;
     default:
         NS_FATAL_ERROR("Invalid scheduling type");
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/simple-ofdm-wimax-phy.cc ns-3.42/src/wimax/model/simple-ofdm-wimax-phy.cc
--- ns-3.41/src/wimax/model/simple-ofdm-wimax-phy.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/model/simple-ofdm-wimax-phy.cc	2024-05-29 15:29:47.224074000 -0700
@@ -36,6 +36,7 @@
 
 #include <cmath>
 #include <string>
+#include <vector>
 
 namespace ns3
 {
@@ -536,31 +537,29 @@
 Ptr<PacketBurst>
 SimpleOfdmWimaxPhy::ConvertBitsToBurst(Bvec buffer)
 {
-    uint8_t init[buffer.size() / 8];
-    uint8_t* pstart = init;
-    uint8_t temp;
+    const auto bufferSize = buffer.size() / 8;
+    std::vector<uint8_t> bytes(bufferSize, 0);
     int32_t j = 0;
     // recreating byte buffer from bit buffer (Bvec)
-    for (uint32_t i = 0; i < buffer.size(); i += 8)
+    for (std::size_t i = 0; i < buffer.size(); i += 8)
     {
-        temp = 0;
-        for (int l = 0; l < 8; l++)
+        uint8_t temp = 0;
+        for (std::size_t l = 0; l < 8; l++)
         {
             bool bin = buffer.at(i + l);
             temp |= (bin << (7 - l));
         }
 
-        *(pstart + j) = temp;
+        bytes[j] = temp;
         j++;
     }
-    uint16_t bufferSize = buffer.size() / 8;
     uint16_t pos = 0;
     Ptr<PacketBurst> RecvBurst = Create<PacketBurst>();
     while (pos < bufferSize)
     {
         uint16_t packetSize = 0;
         // Get the header type: first bit
-        uint8_t ht = (pstart[pos] >> 7) & 0x01;
+        uint8_t ht = (bytes[pos] >> 7) & 0x01;
         if (ht == 1)
         {
             // BW request header. Size is always 8 bytes
@@ -569,15 +568,15 @@
         else
         {
             // Read the size
-            uint8_t Len_MSB = pstart[pos + 1] & 0x07;
-            packetSize = (uint16_t)((uint16_t)(Len_MSB << 8) | (uint16_t)(pstart[pos + 2]));
+            uint8_t Len_MSB = bytes[pos + 1] & 0x07;
+            packetSize = (uint16_t)((uint16_t)(Len_MSB << 8) | (uint16_t)(bytes[pos + 2]));
             if (packetSize == 0)
             {
                 break; // padding
             }
         }
 
-        Ptr<Packet> p = Create<Packet>(&(pstart[pos]), packetSize);
+        Ptr<Packet> p = Create<Packet>(&bytes[pos], packetSize);
         RecvBurst->AddPacket(p);
         pos += packetSize;
     }
@@ -786,20 +785,14 @@
         blockSize = 24;
         break;
     case MODULATION_TYPE_QPSK_12:
-        blockSize = 48;
-        break;
     case MODULATION_TYPE_QPSK_34:
         blockSize = 48;
         break;
     case MODULATION_TYPE_QAM16_12:
-        blockSize = 96;
-        break;
     case MODULATION_TYPE_QAM16_34:
         blockSize = 96;
         break;
     case MODULATION_TYPE_QAM64_23:
-        blockSize = 144;
-        break;
     case MODULATION_TYPE_QAM64_34:
         blockSize = 144;
         break;
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/ss-link-manager.cc ns-3.42/src/wimax/model/ss-link-manager.cc
--- ns-3.41/src/wimax/model/ss-link-manager.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/model/ss-link-manager.cc	2024-05-29 15:29:47.224074000 -0700
@@ -377,7 +377,7 @@
     }
 
     m_nrRngRspsRecvd++;
-    if (m_waitForRngRspEvent.IsRunning())
+    if (m_waitForRngRspEvent.IsPending())
     {
         Simulator::Cancel(m_waitForRngRspEvent);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/ss-net-device.cc ns-3.42/src/wimax/model/ss-net-device.cc
--- ns-3.41/src/wimax/model/ss-net-device.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/model/ss-net-device.cc	2024-05-29 15:29:47.224074000 -0700
@@ -854,7 +854,7 @@
                     Simulator::Cancel(m_linkManager->GetDlMapSyncTimeoutEvent());
                 }
 
-                if (m_lostDlMapEvent.IsRunning())
+                if (m_lostDlMapEvent.IsPending())
                 {
                     Simulator::Cancel(m_lostDlMapEvent);
                 }
@@ -864,7 +864,7 @@
                                                        false,
                                                        m_lostDlMapEvent);
 
-                if (m_dcdWaitTimeoutEvent.IsRunning())
+                if (m_dcdWaitTimeoutEvent.IsPending())
                 {
                     Simulator::Cancel(m_dcdWaitTimeoutEvent);
                 }
@@ -874,7 +874,7 @@
                                                        false,
                                                        m_dcdWaitTimeoutEvent);
 
-                if (m_ucdWaitTimeoutEvent.IsRunning())
+                if (m_ucdWaitTimeoutEvent.IsPending())
                 {
                     Simulator::Cancel(m_ucdWaitTimeoutEvent);
                 }
@@ -890,7 +890,7 @@
                 break;
             }
             case ManagementMessageType::MESSAGE_TYPE_UL_MAP: {
-                if (m_lostUlMapEvent.IsRunning())
+                if (m_lostUlMapEvent.IsPending())
                 {
                     Simulator::Cancel(m_lostUlMapEvent);
                     m_linkManager->ScheduleScanningRestart(m_lostUlMapInterval,
@@ -908,7 +908,7 @@
                 {
                     if (m_linkManager->GetRangingIntervalFound())
                     {
-                        if (m_rangOppWaitTimeoutEvent.IsRunning())
+                        if (m_rangOppWaitTimeoutEvent.IsPending())
                         {
                             Simulator::Cancel(m_rangOppWaitTimeoutEvent);
                         }
@@ -923,7 +923,7 @@
                     SetState(SS_STATE_ACQUIRING_PARAMETERS);
                 }
 
-                if (m_dcdWaitTimeoutEvent.IsRunning())
+                if (m_dcdWaitTimeoutEvent.IsPending())
                 {
                     Simulator::Cancel(m_dcdWaitTimeoutEvent);
                     m_linkManager->ScheduleScanningRestart(m_intervalT1,
@@ -950,7 +950,7 @@
 
                 ProcessUcd(ucd);
 
-                if (m_ucdWaitTimeoutEvent.IsRunning())
+                if (m_ucdWaitTimeoutEvent.IsPending())
                 {
                     Simulator::Cancel(m_ucdWaitTimeoutEvent);
                     m_linkManager->ScheduleScanningRestart(m_intervalT12,
@@ -1029,10 +1029,8 @@
             {
             case ManagementMessageType::MESSAGE_TYPE_REG_REQ:
                 // not yet implemented
-                break;
             case ManagementMessageType::MESSAGE_TYPE_REG_RSP:
                 // intended for base station, ignore
-                break;
             case ManagementMessageType::MESSAGE_TYPE_DSA_REQ:
                 /*from other station as DSA initiation
                  by BS is not supported, ignore*/
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/ss-service-flow-manager.cc ns-3.42/src/wimax/model/ss-service-flow-manager.cc
--- ns-3.41/src/wimax/model/ss-service-flow-manager.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/model/ss-service-flow-manager.cc	2024-05-29 15:29:47.224074000 -0700
@@ -182,7 +182,7 @@
     m_dsaReqRetries++;
     p->AddHeader(ManagementMessageType(ManagementMessageType::MESSAGE_TYPE_DSA_REQ));
 
-    if (m_dsaRspTimeoutEvent.IsRunning())
+    if (m_dsaRspTimeoutEvent.IsPending())
     {
         Simulator::Cancel(m_dsaRspTimeoutEvent);
     }
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/model/wimax-tlv.cc ns-3.42/src/wimax/model/wimax-tlv.cc
--- ns-3.41/src/wimax/model/wimax-tlv.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/model/wimax-tlv.cc	2024-05-29 15:29:47.228073800 -0700
@@ -438,19 +438,12 @@
             break;
         }
         case ARQ_RETRY_TIMEOUT_Transmitter_Delay:
-            break;
         case ARQ_RETRY_TIMEOUT_Receiver_Delay:
-            break;
         case ARQ_BLOCK_LIFETIME:
-            break;
         case ARQ_SYNC_LOSS:
-            break;
         case ARQ_DELIVER_IN_ORDER:
-            break;
         case ARQ_PURGE_TIMEOUT:
-            break;
         case ARQ_BLOCK_SIZE:
-            break;
         case reserved2:
             break;
         case CS_Specification: {
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/mac-messages-test.cc ns-3.42/src/wimax/test/mac-messages-test.cc
--- ns-3.41/src/wimax/test/mac-messages-test.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/test/mac-messages-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -123,9 +123,9 @@
 };
 
 Ns3WimaxMacMessagesTestSuite::Ns3WimaxMacMessagesTestSuite()
-    : TestSuite("wimax-mac-messages", UNIT)
+    : TestSuite("wimax-mac-messages", Type::UNIT)
 {
-    AddTestCase(new DsaRequestTestCase, TestCase::QUICK);
+    AddTestCase(new DsaRequestTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxMacMessagesTestSuite ns3WimaxMacMessagesTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/phy-test.cc ns-3.42/src/wimax/test/phy-test.cc
--- ns-3.41/src/wimax/test/phy-test.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/test/phy-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -188,10 +188,10 @@
 };
 
 Ns3WimaxPhyTestSuite::Ns3WimaxPhyTestSuite()
-    : TestSuite("wimax-phy-layer", UNIT)
+    : TestSuite("wimax-phy-layer", Type::UNIT)
 {
-    AddTestCase(new Ns3WimaxSNRtoBLERTestCase, TestCase::QUICK);
-    AddTestCase(new Ns3WimaxSimpleOFDMTestCase, TestCase::QUICK);
+    AddTestCase(new Ns3WimaxSNRtoBLERTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new Ns3WimaxSimpleOFDMTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxPhyTestSuite ns3WimaxPhyTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/qos-test.cc ns-3.42/src/wimax/test/qos-test.cc
--- ns-3.41/src/wimax/test/qos-test.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/test/qos-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -311,10 +311,10 @@
 };
 
 Ns3WimaxQoSTestSuite::Ns3WimaxQoSTestSuite()
-    : TestSuite("wimax-qos", SYSTEM)
+    : TestSuite("wimax-qos", Type::SYSTEM)
 {
-    AddTestCase(new Ns3WimaxSFTypeTestCase, TestCase::QUICK);
-    AddTestCase(new Ns3WimaxSchedulingTestCase, TestCase::QUICK);
+    AddTestCase(new Ns3WimaxSFTypeTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new Ns3WimaxSchedulingTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxQoSTestSuite ns3WimaxQoSTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/ss-mac-test.cc ns-3.42/src/wimax/test/ss-mac-test.cc
--- ns-3.41/src/wimax/test/ss-mac-test.cc	2024-02-09 14:44:08.625795400 -0800
+++ ns-3.42/src/wimax/test/ss-mac-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -166,10 +166,10 @@
 };
 
 Ns3WimaxSSMacTestSuite::Ns3WimaxSSMacTestSuite()
-    : TestSuite("wimax-ss-mac-layer", UNIT)
+    : TestSuite("wimax-ss-mac-layer", Type::UNIT)
 {
-    AddTestCase(new Ns3WimaxNetworkEntryTestCase, TestCase::QUICK);
-    AddTestCase(new Ns3WimaxManagementConnectionsTestCase, TestCase::QUICK);
+    AddTestCase(new Ns3WimaxNetworkEntryTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new Ns3WimaxManagementConnectionsTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxSSMacTestSuite ns3WimaxSSMacTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/wimax-fragmentation-test.cc ns-3.42/src/wimax/test/wimax-fragmentation-test.cc
--- ns-3.41/src/wimax/test/wimax-fragmentation-test.cc	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/src/wimax/test/wimax-fragmentation-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -155,9 +155,9 @@
 };
 
 Ns3WimaxFragmentationTestSuite::Ns3WimaxFragmentationTestSuite()
-    : TestSuite("wimax-fragmentation", UNIT)
+    : TestSuite("wimax-fragmentation", Type::UNIT)
 {
-    AddTestCase(new Ns3WimaxFragmentationTestCase, TestCase::QUICK);
+    AddTestCase(new Ns3WimaxFragmentationTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxFragmentationTestSuite ns3WimaxFragmentationTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/wimax-service-flow-test.cc ns-3.42/src/wimax/test/wimax-service-flow-test.cc
--- ns-3.41/src/wimax/test/wimax-service-flow-test.cc	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/src/wimax/test/wimax-service-flow-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -163,9 +163,9 @@
 };
 
 Ns3WimaxServiceFlowTestSuite::Ns3WimaxServiceFlowTestSuite()
-    : TestSuite("wimax-service-flow", UNIT)
+    : TestSuite("wimax-service-flow", Type::UNIT)
 {
-    AddTestCase(new Ns3WimaxSfCreationTestCase, TestCase::QUICK);
+    AddTestCase(new Ns3WimaxSfCreationTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxServiceFlowTestSuite ns3WimaxServiceFlowTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/src/wimax/test/wimax-tlv-test.cc ns-3.42/src/wimax/test/wimax-tlv-test.cc
--- ns-3.41/src/wimax/test/wimax-tlv-test.cc	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/src/wimax/test/wimax-tlv-test.cc	2024-05-29 15:29:47.228073800 -0700
@@ -224,10 +224,10 @@
 };
 
 Ns3WimaxTlvTestSuite::Ns3WimaxTlvTestSuite()
-    : TestSuite("wimax-tlv", UNIT)
+    : TestSuite("wimax-tlv", Type::UNIT)
 {
-    AddTestCase(new Ns3WimaxCsParamTlvTestCase, TestCase::QUICK);
-    AddTestCase(new Ns3WimaxSfTlvTestCase, TestCase::QUICK);
+    AddTestCase(new Ns3WimaxCsParamTlvTestCase, TestCase::Duration::QUICK);
+    AddTestCase(new Ns3WimaxSfTlvTestCase, TestCase::Duration::QUICK);
 }
 
 static Ns3WimaxTlvTestSuite ns3WimaxTlvTestSuite; ///< the test suite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/test.py ns-3.42/test.py
--- ns-3.41/test.py	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/test.py	2024-05-29 15:29:47.228073800 -0700
@@ -169,10 +169,39 @@
     # can depend on ns3 configuration variables.  For example,
     # when NSC was in the codebase, we could write:
     #
-    #     ("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False"),
+    #     ("tcp-nsc-lfn", "NSC_ENABLED == True", "NSC_ENABLED == False", "QUICK"),
     #
     cpp_examples = get_list_from_file(examples_to_run_path, "cpp_examples")
-    for example_name, do_run, do_valgrind_run in cpp_examples:
+    for cpp_example in cpp_examples:
+        # Old example specification did not include
+        # 'fullness', so for compatibility,
+        # allow 3 components, & set the 'fullness' to QUICK
+        if len(cpp_example) == 3:
+            example_name, do_run, do_valgrind_run = cpp_example
+            fullness = "QUICK"
+        elif len(cpp_example) == 4:
+            example_name, do_run, do_valgrind_run, fullness = cpp_example
+            fullness: str = fullness.upper()
+
+            if fullness != "QUICK" and fullness != "EXTENSIVE" and fullness != "TAKES_FOREVER":
+                raise ValueError(
+                    f"Invalid value provided for example '{example_name}' "
+                    + f"expected 'QUICK', 'EXTENSIVE', or 'TAKES_FOREVER', got: '{fullness}'"
+                )
+        else:
+            # If we have the name of the example we're error-ing for, provide it
+            # Otherwise, just give a generic message
+            if len(cpp_example) >= 1:
+                raise RuntimeError(
+                    f"Incorrect number of fields declaration of example '{cpp_example[0]}', "
+                    + f"expected 3, or 4 got: {len(cpp_example)}"
+                )
+            else:
+                raise RuntimeError(
+                    f"Incorrect number of fields declaration of example, "
+                    + f"expected 3, or 4 got: {len(cpp_example)}"
+                )
+
         # Separate the example name from its arguments.
         example_name_original = example_name
         example_name_parts = example_name.split(" ", 1)
@@ -200,12 +229,12 @@
                 example_name = "%s %s" % (example_name, example_arguments)
 
             # Add this example.
-            example_tests.append((example_name, example_path, do_run, do_valgrind_run))
+            example_tests.append((example_name, example_path, do_run, do_valgrind_run, fullness))
             example_names_original.append(example_name_original)
 
     # Each tuple in the Python list of examples to run contains
     #
-    #     (example_name, do_run)
+    #     (example_name, do_run, fullness)
     #
     # where example_name is the Python script to be run and
     # do_run is a condition under which to run the example.
@@ -213,10 +242,32 @@
     # Note that the condition is a Python statement that can
     # depend on ns3 configuration variables.  For example,
     #
-    #     ("brite-generic-example", "ENABLE_BRITE == True", "False"),
+    #     ("brite-generic-example.py", "ENABLE_BRITE == True", "QUICK"),
     #
     python_examples = get_list_from_file(examples_to_run_path, "python_examples")
-    for example_name, do_run in python_examples:
+    # Old example specification did not include
+    # 'fullness', so for compatibility,
+    # allow 2 components, & set the 'fullness' to QUICK
+    for python_example in python_examples:
+        if len(python_example) == 2:
+            example_name, do_run = python_example
+            fullness = "QUICK"
+        elif len(python_example) == 3:
+            example_name, do_run, fullness = python_example
+        else:
+            # If we have the name of the example we're error-ing for, provide it
+            # Otherwise, just give a generic message
+            if len(python_example) >= 1:
+                raise RuntimeError(
+                    f"Incorrect number of fields declaration of example '{python_example[0]}', "
+                    + f"expected 2, or 3 got: {len(python_example)}"
+                )
+            else:
+                raise RuntimeError(
+                    f"Incorrect number of fields declaration of example, "
+                    + f"expected 2, or 3 got: {len(python_example)}"
+                )
+
         # Separate the example name from its arguments.
         example_name_parts = example_name.split(" ", 1)
         if len(example_name_parts) == 1:
@@ -237,7 +288,7 @@
                 example_path = "%s %s" % (example_path, example_arguments)
 
             # Add this example.
-            python_tests.append((example_path, do_run))
+            python_tests.append((example_path, do_run, fullness))
 
 
 #
@@ -800,8 +851,8 @@
 # no longer needed.  If it is needed again in the future, define the
 # below variable again, and remove the alternative definition to None
 #
-# VALGRIND_SUPPRESSIONS_FILE = "testpy.supp"
-VALGRIND_SUPPRESSIONS_FILE = None
+VALGRIND_SUPPRESSIONS_FILE = ".ns3.supp"
+# VALGRIND_SUPPRESSIONS_FILE = None
 
 
 def run_job_synchronously(shell_command, directory, valgrind, is_python, build_path=""):
@@ -1657,7 +1708,7 @@
     if len(args.suite) == 0 and len(args.example) == 0 and len(args.pyexample) == 0:
         if len(args.constrain) == 0 or args.constrain == "example":
             if ENABLE_EXAMPLES:
-                for name, test, do_run, do_valgrind_run in example_tests:
+                for name, test, do_run, do_valgrind_run, fullness in example_tests:
                     # Remove any arguments and directory names from test.
                     test_name = test.split(" ", 1)[0]
                     test_name = os.path.basename(test_name)
@@ -1691,6 +1742,22 @@
                             if args.verbose:
                                 print("Queue %s" % test)
 
+                            if args.fullness == "QUICK" and fullness != "QUICK":
+                                job.set_is_skip(True)
+                                job.set_skip_reason(
+                                    f"skip {fullness} examples when QUICK run selected"
+                                )
+                            elif (
+                                args.fullness == "EXTENSIVE"
+                                and fullness != "EXTENSIVE"
+                                and fullness != "QUICK"
+                            ):
+                                job.set_is_skip(True)
+                                job.set_skip_reason(
+                                    f"skip {fullness} examples when EXTENSIVE run selected"
+                                )
+                            # TAKES_FOREVER includes everything, so no need to exclude anything
+
                             input_queue.put(job)
                             jobs = jobs + 1
                             total_tests = total_tests + 1
@@ -1755,7 +1822,7 @@
     #
     if len(args.suite) == 0 and len(args.example) == 0 and len(args.pyexample) == 0:
         if len(args.constrain) == 0 or args.constrain == "pyexample":
-            for test, do_run in python_tests:
+            for test, do_run, fullness in python_tests:
                 # Remove any arguments and directory names from test.
                 test_name = test.split(" ", 1)[0]
                 test_name = os.path.basename(test_name)
@@ -1797,6 +1864,20 @@
                         if args.verbose:
                             print("Queue %s" % test)
 
+                        if args.fullness == "QUICK" and fullness != "QUICK":
+                            job.set_is_skip(True)
+                            job.set_skip_reason(f"skip {fullness} examples when QUICK run selected")
+                        elif (
+                            args.fullness == "EXTENSIVE"
+                            and fullness != "EXTENSIVE"
+                            and fullness != "QUICK"
+                        ):
+                            job.set_is_skip(True)
+                            job.set_skip_reason(
+                                f"skip {fullness} examples when EXTENSIVE run selected"
+                            )
+                        # TAKES_FOREVER includes everything, so no need to exclude anything
+
                         input_queue.put(job)
                         jobs = jobs + 1
                         total_tests = total_tests + 1
@@ -1932,6 +2013,7 @@
                     f.write("  <Result>VALGR</Result>\n")
                 elif status == "SKIP":
                     f.write("  <Result>SKIP</Result>\n")
+                    f.write("  <Reason>%s</Reason>\n" % job.skip_reason)
                 else:
                     f.write("  <Result>CRASH</Result>\n")
 
@@ -2002,9 +2084,15 @@
                             post = contents.find("</Result>")
                             contents = contents[:pre] + "VALGR" + contents[post:]
                         f_to.write(contents)
-                        et = ET.parse(job.tmp_file_name)
-                        if et.find("Result").text in ["PASS", "SKIP"]:
-                            failed_jobs.pop()
+                        # When running with sanitizers, the program may
+                        # crash before ever writing the expected xml
+                        # output file
+                        try:
+                            et = ET.parse(job.tmp_file_name)
+                            if et.find("Result").text in ["PASS", "SKIP"]:
+                                failed_jobs.pop()
+                        except:
+                            pass
                 else:
                     with open(xml_results_file, "a", encoding="utf-8") as f:
                         f.write("<Test>\n")
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/check-style-clang-format.py ns-3.42/utils/check-style-clang-format.py
--- ns-3.41/utils/check-style-clang-format.py	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/check-style-clang-format.py	2024-05-29 15:29:47.228073800 -0700
@@ -60,10 +60,12 @@
 DIRECTORIES_TO_SKIP = [
     "__pycache__",
     ".git",
+    ".venv",
     "bindings",
     "build",
     "cmake-cache",
     "testpy-output",
+    "venv",
 ]
 
 # List of files entirely copied from elsewhere that should not be checked,
@@ -80,51 +82,55 @@
 
 FILE_EXTENSIONS_TO_CHECK_INCLUDE_PREFIXES = FILE_EXTENSIONS_TO_CHECK_FORMATTING
 
-FILE_EXTENSIONS_TO_CHECK_WHITESPACE = [
+FILE_EXTENSIONS_TO_CHECK_TABS = [
     ".c",
     ".cc",
-    ".click",
     ".cmake",
-    ".conf",
     ".css",
-    ".dot",
-    ".gnuplot",
-    ".gp",
     ".h",
     ".html",
     ".js",
     ".json",
     ".m",
     ".md",
+    ".pl",
+    ".py",
+    ".rst",
+    ".sh",
+    ".toml",
+    ".yml",
+]
+
+FILES_TO_CHECK_TABS = [
+    ".clang-format",
+    ".clang-tidy",
+    ".codespellrc",
+    "CMakeLists.txt",
+    "codespell-ignored-lines",
+    "codespell-ignored-words",
+    "ns3",
+]
+
+FILE_EXTENSIONS_TO_CHECK_WHITESPACE = FILE_EXTENSIONS_TO_CHECK_TABS + [
+    ".click",
+    ".cfg",
+    ".conf",
+    ".dot",
+    ".gnuplot",
+    ".gp",
     ".mob",
     ".ns_params",
     ".ns_movements",
     ".params",
-    ".pl",
     ".plt",
-    ".py",
-    ".rst",
     ".seqdiag",
-    ".sh",
     ".txt",
-    ".yml",
 ]
 
-FILES_TO_CHECK_WHITESPACE = [
+FILES_TO_CHECK_WHITESPACE = FILES_TO_CHECK_TABS + [
     "Makefile",
-    "ns3",
 ]
 
-FILE_EXTENSIONS_TO_CHECK_TABS = [
-    ".c",
-    ".cc",
-    ".h",
-    ".md",
-    ".py",
-    ".rst",
-    ".sh",
-    ".yml",
-]
 TAB_SIZE = 4
 
 
@@ -141,9 +147,7 @@
 
     _, directory = os.path.split(dirpath)
 
-    return not (
-        directory in DIRECTORIES_TO_SKIP or (directory.startswith(".") and directory != ".")
-    )
+    return directory not in DIRECTORIES_TO_SKIP
 
 
 def should_analyze_file(
@@ -165,9 +169,9 @@
     if filename in FILES_TO_SKIP:
         return False
 
-    basename, extension = os.path.splitext(filename)
+    extension = os.path.splitext(filename)[1]
 
-    return basename in files_to_check or extension in file_extensions_to_check
+    return filename in files_to_check or extension in file_extensions_to_check
 
 
 def find_files_to_check_style(
@@ -220,7 +224,7 @@
         if should_analyze_file(f, FILES_TO_CHECK_WHITESPACE, FILE_EXTENSIONS_TO_CHECK_WHITESPACE):
             files_to_check_whitespace.append(f)
 
-        if should_analyze_file(f, [], FILE_EXTENSIONS_TO_CHECK_TABS):
+        if should_analyze_file(f, FILES_TO_CHECK_TABS, FILE_EXTENSIONS_TO_CHECK_TABS):
             files_to_check_tabs.append(f)
 
     return (
@@ -769,7 +773,9 @@
         print(e)
         sys.exit(1)
 
-    if all_checks_successful:
-        sys.exit(0)
-    else:
+    if not all_checks_successful:
+        if args.verbose:
+            print("")
+            print('NOTE: To fix the files automatically, run this script with the flag "--fix"')
+
         sys.exit(1)
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/codespell-ignored-lines ns-3.42/utils/codespell-ignored-lines
--- ns-3.41/utils/codespell-ignored-lines	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/codespell-ignored-lines	2024-05-29 15:29:47.228073800 -0700
@@ -81,10 +81,14 @@
  * Copyright (c) 2022 Universita' degli Studi di Napoli Federico II
  * Copyright (c) 2022 Universita' degli Studi di Napoli "Federico II"
  * Copyright (c) 2023 Universita' degli Studi di Napoli Federico II
+ * Copyright (c) 2024 Universita' degli Studi di Napoli Federico II
 
 ./src/core/examples/hash-example.cc
 6ed21de2  brand-newness       peripherial
 
+./src/core/model/trickle-timer.cc:120
+    return std::countr_zero(m_ticks);
+
 ./src/dsr/model/dsr-routing.cc:243, 246, 3360, 3363
             .AddAttribute("GratReplyHoldoff",
                           MakeTimeAccessor(&DsrRouting::m_gratReplyHoldoff),
@@ -161,3 +165,6 @@
   * (lte) Struct member `pfsFlowPerf_t::lastTtiBytesTrasmitted` in file `pf-ff-mac-scheduler.h` was renamed `fdbetsFlowPerf_t::lastTtiBytesTransmitted`.
 * The spelling of the attribute `IntialCellVoltage` from `LiIonEnergySource` was corrected to `InitialCellVoltage`; this will affect existing users who were using the attribute with the misspelling.
 * The attribute `Recievers` in class `YansWifiPhy` was misspelled, so this has been corrected to `Receivers`.
+
+./doc/manual/source/working-with-docker.rst
+    067a8b748816715d93ede9099132d943c04b13fcc23b3b8a7e21d23c1096cc2a
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/codespell-ignored-words ns-3.42/utils/codespell-ignored-words
--- ns-3.41/utils/codespell-ignored-words	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/codespell-ignored-words	2024-05-29 15:29:47.228073800 -0700
@@ -26,6 +26,7 @@
 
 #Wi-Fi
 aci
+fils
 
 #Wimax
 aas
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/create-module.py ns-3.42/utils/create-module.py
--- ns-3.41/utils/create-module.py	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/create-module.py	2024-05-29 15:29:47.228073800 -0700
@@ -214,10 +214,10 @@
 }};
 
 {CAPITALIZED}TestSuite::{CAPITALIZED}TestSuite()
-    : TestSuite("{MODULE}", UNIT)
+    : TestSuite("{MODULE}", Type::UNIT)
 {{
-    // TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
-    AddTestCase(new {CAPITALIZED}TestCase1, TestCase::QUICK);
+    // Duration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
+    AddTestCase(new {CAPITALIZED}TestCase1, TestCase::Duration::QUICK);
 }}
 
 // Do not forget to allocate an instance of this TestSuite
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/print-introspected-doxygen.cc ns-3.42/utils/print-introspected-doxygen.cc
--- ns-3.41/utils/print-introspected-doxygen.cc	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/print-introspected-doxygen.cc	2024-05-29 15:29:47.228073800 -0700
@@ -1227,15 +1227,7 @@
        << "AttributeValue implementation for " << name << "\n";
     if (seeBase)
     {
-        // Some classes don't live in ns3::.  Yuck
-        if (name != "IeMeshId")
-        {
-            os << seeAlso << "ns3::" << name << "\n";
-        }
-        else
-        {
-            os << seeAlso << "ns3::dot11s::" << name << "\n";
-        }
+        os << seeAlso << "ns3::" << name << "\n";
     }
     os << commentStop;
 
@@ -1271,20 +1263,12 @@
     os << seeAlso << "AttributeValue" << std::endl;
     os << commentStop;
 
-    // Copy ctor: <name>Value::<name>Value
-    os << commentStart << functionStart << name << qualClass << "::" << valClass;
-    if ((name == "EmptyAttribute") || (name == "ObjectPtrContainer"))
-    {
-        // Just default constructors.
-        os << "()\n";
-    }
-    else
-    {
-        // Copy constructors
-        os << "(const " << type << " & value)\n"
-           << "Copy constructor.\n"
-           << argument << "[in] value The " << name << " value to copy.\n";
-    }
+    // Ctor: <name>Value::<name>Value
+    os << commentStart << functionStart << qualClass << "::" << valClass;
+    // Constructors
+    os << "(const " << type << " & value)\n"
+       << "Constructor.\n"
+       << argument << "[in] value The " << name << " value to use.\n";
     os << commentStop;
 
     // <name>Value::Get () const
@@ -1430,7 +1414,6 @@
       { "Box",            "Box",            true,  "box.h"              },
       { "DataRate",       "DataRate",       true,  "data-rate.h"        },
       { "Length",         "Length",         true,  "length.h"           },
-      { "IeMeshId",       "IeMeshId",       true,  "ie-dot11s-id.h"     },
       { "Ipv4Address",    "Ipv4Address",    true,  "ipv4-address.h"     },
       { "Ipv4Mask",       "Ipv4Mask",       true,  "ipv4-address.h"     },
       { "Ipv6Address",    "Ipv6Address",    true,  "ipv6-address.h"     },
@@ -1439,9 +1422,6 @@
       { "Mac48Address",   "Mac48Address",   true,  "mac48-address.h"    },
       { "Mac64Address",   "Mac64Address",   true,  "mac64-address.h"    },
       { "ObjectFactory",  "ObjectFactory",  true,  "object-factory.h"   },
-      { "OrganizationIdentifier",
-                          "OrganizationIdentifier",
-                                            true,  "vendor-specific-action.h" },
       { "Priomap",        "Priomap",        true,  "prio-queue-disc.h"  },
       { "QueueSize",      "QueueSize",      true,  "queue-size.h"       },
       { "Rectangle",      "Rectangle",      true,  "rectangle.h"        },
@@ -1449,7 +1429,6 @@
       { "TypeId",         "TypeId",         true,  "type-id.h"          },
       { "UanModesList",   "UanModesList",   true,  "uan-tx-mode.h"      },
       { "ValueClassTest", "ValueClassTest", false, "attribute-test-suite.cc" /* core/test/ */  },
-      { "Vector",         "Vector",         true,  "vector.h"           },
       { "Vector2D",       "Vector2D",       true,  "vector.h"           },
       { "Vector3D",       "Vector3D",       true,  "vector.h"           },
       { "Waypoint",       "Waypoint",       true,  "waypoint.h"         },
@@ -1457,11 +1436,10 @@
 
       // All three (Value, Access and Checkers) defined, but custom
       { "Boolean",        "bool",           false, "boolean.h"          },
-      { "Callback",       "Callback",       true,  "callback.h"         },
+      { "Callback",       "CallbackBase",   true,  "callback.h"         },
       { "Double",         "double",         false, "double.h"           },
-      { "Enum",           "int",            false, "enum.h"             },
+      { "Enum",           "T",              false, "enum.h"             },
       { "Integer",        "int64_t",        false, "integer.h"          },
-      { "Pointer",        "Pointer",        false, "pointer.h"          },
       { "String",         "std::string",    false, "string.h"           },
       { "Time",           "Time",           true,  "nstime.h"           },
       { "Uinteger",       "uint64_t",       false, "uinteger.h"         },
@@ -1476,17 +1454,6 @@
         ++i;
     }
 
-    // Special cases
-    PrintAttributeValueSection(os, "EmptyAttribute", false);
-    PrintAttributeValueWithName(os, "EmptyAttribute", "EmptyAttribute", "attribute.h");
-
-    PrintAttributeValueSection(os, "ObjectPtrContainer", false);
-    PrintAttributeValueWithName(os,
-                                "ObjectPtrContainer",
-                                "ObjectPtrContainer",
-                                "object-ptr-container.h");
-    PrintMakeChecker(os, "ObjectPtrContainer", "object-ptr-container.h");
-
     PrintAttributeValueSection(os, "ObjectVector", false);
     PrintMakeAccessors(os, "ObjectVector");
     PrintMakeChecker(os, "ObjectVector", "object-vector.h");
@@ -1495,19 +1462,6 @@
     PrintMakeAccessors(os, "ObjectMap");
     PrintMakeChecker(os, "ObjectMap", "object-map.h");
 
-    PrintAttributeValueSection(os, "Pair", false);
-    PrintAttributeValueWithName(os, "Pair", "std::pair<A, B>", "pair.h");
-    PrintMakeChecker(os, "Pair", "pair.h");
-
-    PrintAttributeValueSection(os, "Tuple", false);
-    PrintAttributeValueWithName(os, "Tuple", "std::tuple<Args...>", "tuple.h");
-    PrintMakeChecker(os, "Tuple", "tuple.h");
-
-    // AttributeContainer is already documented.
-    // PrintAttributeValueSection  (os, "AttributeContainer", false);
-    // PrintAttributeValueWithName (os, "AttributeContainer", "AttributeContainer",
-    // "attribute-container.h");
-    PrintMakeChecker(os, "AttributeContainer", "attribute-container.h");
 } // PrintAttributeImplementations ()
 
 /***************************************************************
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/python-unit-tests.py ns-3.42/utils/python-unit-tests.py
--- ns-3.41/utils/python-unit-tests.py	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/python-unit-tests.py	2024-05-29 15:29:47.228073800 -0700
@@ -202,7 +202,7 @@
         @param self this object
         @return None
         """
-        ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123))
+        ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.UintegerValue(123))
         # hm.. no Config.Get?
 
     def testSocket(self):
@@ -212,7 +212,7 @@
         """
         nc = ns.NodeContainer(1)
         node = nc.Get(0)
-        internet = ns.CreateObject("InternetStackHelper")
+        internet = ns.InternetStackHelper()
         internet.Install(node)
         self._received_packet = None
 
@@ -228,19 +228,15 @@
         """
         )
 
-        sink = ns.network.Socket.CreateSocket(
-            node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
-        )
-        sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80).ConvertTo())
+        sink = ns.Socket.CreateSocket(node, ns.TypeId.LookupByName("ns3::UdpSocketFactory"))
+        sink.Bind(ns.InetSocketAddress(ns.Ipv4Address.GetAny(), 80).ConvertTo())
         sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback_test_socket(python_rx_callback))
 
-        source = ns.network.Socket.CreateSocket(
-            node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
-        )
+        source = ns.Socket.CreateSocket(node, ns.TypeId.LookupByName("ns3::UdpSocketFactory"))
         source.SendTo(
-            ns.network.Packet(19),
+            ns.Packet(19),
             0,
-            ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo(),
+            ns.InetSocketAddress(ns.Ipv4Address("127.0.0.1"), 80).ConvertTo(),
         )
 
         ns.Simulator.Run()
@@ -255,28 +251,28 @@
         @param self this object
         @return None
         """
-        # Templated class DropTailQueue<Packet> in C++
-        queue = ns.CreateObject("DropTailQueue<Packet>")
-        queueSizeValue = ns.network.QueueSizeValue(ns.network.QueueSize("500p"))
+        # Templated class DropTailQueue[ns.Packet] in C++
+        queue = ns.CreateObject[ns.DropTailQueue[ns.Packet]]()
+        queueSizeValue = ns.QueueSizeValue(ns.QueueSize("500p"))
         queue.SetAttribute("MaxSize", queueSizeValue)
 
-        limit = ns.network.QueueSizeValue()
+        limit = ns.QueueSizeValue()
         queue.GetAttribute("MaxSize", limit)
-        self.assertEqual(limit.Get(), ns.network.QueueSize("500p"))
+        self.assertEqual(limit.Get(), ns.QueueSize("500p"))
 
         ## -- object pointer values
-        mobility = ns.CreateObject("RandomWaypointMobilityModel")
-        ptr = ns.CreateObject("PointerValue")
+        mobility = ns.CreateObject[ns.RandomWaypointMobilityModel]()
+        ptr = ns.PointerValue()
         mobility.GetAttribute("PositionAllocator", ptr)
-        self.assertEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
+        self.assertEqual(ptr.GetObject(), ns.Ptr["Object"](ns.cppyy.nullptr))
 
-        pos = ns.mobility.ListPositionAllocator()
+        pos = ns.ListPositionAllocator()
         ptr.SetObject(pos)
         mobility.SetAttribute("PositionAllocator", ptr)
 
-        ptr2 = ns.CreateObject("PointerValue")
+        ptr2 = ns.PointerValue()
         mobility.GetAttribute("PositionAllocator", ptr2)
-        self.assertNotEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
+        self.assertNotEqual(ptr.GetObject(), ns.Ptr["Object"](ns.cppyy.nullptr))
 
         # Delete Ptr<>'s on the python side to let C++ clean them
         del queue, mobility, ptr, ptr2
@@ -286,8 +282,8 @@
         @param self this object
         @return None
         """
-        csma = ns.CreateObject("CsmaNetDevice")
-        channel = ns.CreateObject("CsmaChannel")
+        csma = ns.CreateObject[ns.CsmaNetDevice]()
+        channel = ns.CreateObject[ns.CsmaChannel]()
         csma.Attach(channel)
 
         c1 = csma.GetChannel()
@@ -324,7 +320,7 @@
         test4Buffer = create_string_buffer(b"this is a test option", BUFFLEN)
         test4 = c_char_p(test4Buffer.raw)
 
-        cmd = ns.core.CommandLine(__file__)
+        cmd = ns.CommandLine(__file__)
         cmd.AddValue("Test1", "this is a test option", test1)
         cmd.AddValue("Test2", "this is a test option", test2)
         cmd.AddValue["double"]("Test3", "this is a test option", test3)
@@ -351,7 +347,7 @@
         """
 
         ## MyNode class
-        class MyNode(ns.network.Node):
+        class MyNode(ns.Node):
             def GetLocalTime(self) -> ns.Time:
                 return ns.Seconds(10)
 
@@ -367,20 +363,20 @@
         """
         ns.Simulator.Destroy()
 
-        nodes = ns.network.NodeContainer()
+        nodes = ns.NodeContainer()
         nodes.Create(2)
 
-        pointToPoint = ns.point_to_point.PointToPointHelper()
-        pointToPoint.SetDeviceAttribute("DataRate", ns.core.StringValue("5Mbps"))
-        pointToPoint.SetChannelAttribute("Delay", ns.core.StringValue("2ms"))
+        pointToPoint = ns.PointToPointHelper()
+        pointToPoint.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
+        pointToPoint.SetChannelAttribute("Delay", ns.StringValue("2ms"))
 
         devices = pointToPoint.Install(nodes)
 
-        stack = ns.internet.InternetStackHelper()
+        stack = ns.InternetStackHelper()
         stack.Install(nodes)
 
-        address = ns.internet.Ipv4AddressHelper()
-        address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
+        address = ns.Ipv4AddressHelper()
+        address.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
 
         interfaces = address.Assign(devices)
 
@@ -401,7 +397,7 @@
         )
 
         ## EchoServer application class
-        class EchoServer(ns.applications.Application):
+        class EchoServer(ns.Application):
             LOGGING = False
             ECHO_PORT = 1234
             socketToInstanceDict = {}
@@ -419,13 +415,11 @@
                 ## Listen port for the server
                 self.port = port
                 ## Socket used by the server to listen to port
-                self.m_socket = ns.network.Socket.CreateSocket(
-                    node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
+                self.m_socket = ns.Socket.CreateSocket(
+                    node, ns.TypeId.LookupByName("ns3::UdpSocketFactory")
                 )
                 self.m_socket.Bind(
-                    ns.network.InetSocketAddress(
-                        ns.network.Ipv4Address.GetAny(), self.port
-                    ).ConvertTo()
+                    ns.InetSocketAddress(ns.Ipv4Address.GetAny(), self.port).ConvertTo()
                 )
                 self.m_socket.SetRecvCallback(ns.make_rx_callback(EchoServer._Receive))
                 EchoServer.socketToInstanceDict[self.m_socket] = self
@@ -507,18 +501,18 @@
 
         serverApps = ns.ApplicationContainer()
         serverApps.Add(echoServer)
-        serverApps.Start(ns.core.Seconds(1.0))
-        serverApps.Stop(ns.core.Seconds(10.0))
+        serverApps.Start(ns.Seconds(1.0))
+        serverApps.Stop(ns.Seconds(10.0))
 
         address = interfaces.GetAddress(1).ConvertTo()
-        echoClient = ns.applications.UdpEchoClientHelper(address, EchoServer.ECHO_PORT)
-        echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(10))
-        echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
-        echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(101))
+        echoClient = ns.UdpEchoClientHelper(address, EchoServer.ECHO_PORT)
+        echoClient.SetAttribute("MaxPackets", ns.UintegerValue(10))
+        echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
+        echoClient.SetAttribute("PacketSize", ns.UintegerValue(101))
 
         clientApps = echoClient.Install(nodes.Get(0))
-        clientApps.Start(ns.core.Seconds(2.0))
-        clientApps.Stop(ns.core.Seconds(10.0))
+        clientApps.Start(ns.Seconds(2.0))
+        clientApps.Stop(ns.Seconds(10.0))
 
         ns.Simulator.Run()
         ns.Simulator.Destroy()
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-clang.yml ns-3.42/utils/tests/gitlab-ci-clang.yml
--- ns-3.41/utils/tests/gitlab-ci-clang.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-clang.yml	2024-05-29 15:29:47.228073800 -0700
@@ -4,11 +4,10 @@
 # "RELEASE", that has a value "weekly". Also, a variable "CLANG" should be set
 # to True.
 
-# We support CLANG versions 10 through 16
-# We test only CLANG 10 on Ubuntu 20.04 and CLANG 16 on Ubuntu 23.04
+# We support CLANG versions 10 through 18
+# We test only CLANG 10 on Ubuntu 20.04 and CLANG 18 on Ubuntu 24.04
 
-.weekly-clang-ubuntu20.04:
-  image: ubuntu:20.04
+.weekly-clang-ubuntu:
   extends: .base-build
   rules:
     - if: $RELEASE == "weekly"
@@ -20,6 +19,7 @@
     - DEBIAN_FRONTEND=noninteractive apt install -y
       clang-$CLANG cmake ninja-build ccache build-essential
       libboost-all-dev
+      libeigen3-dev
       libgtk-3-0 libgtk-3-dev
       libgsl-dev $LIBGSL gsl-bin
       libsqlite3-dev sqlite3
@@ -27,29 +27,18 @@
       ssh
   variables:
     COMPILER: clang++-$CLANG
+
+.weekly-clang-ubuntu20.04:
+  image: ubuntu:20.04
+  extends: .weekly-clang-ubuntu
+  variables:
     LIBGSL: libgsl23
+    EXTRA_OPTIONS: --disable-eigen
 
-.weekly-clang-ubuntu23.04:
-  image: ubuntu:23.04
-  extends: .base-build
-  rules:
-    - if: $RELEASE == "weekly"
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-      allow_failure: true
-  before_script:
-    - apt update
-    - apt upgrade -y
-    - DEBIAN_FRONTEND=noninteractive apt install -y
-      clang-$CLANG cmake ninja-build ccache build-essential
-      libboost-all-dev
-      libeigen3-dev
-      libgtk-3-0 libgtk-3-dev
-      libgsl-dev $LIBGSL gsl-bin
-      libsqlite3-dev sqlite3
-      libxml2 libxml2-dev
-      ssh
+.weekly-clang-ubuntu24.04:
+  image: ubuntu:24.04
+  extends: .weekly-clang-ubuntu
   variables:
-    COMPILER: clang++-$CLANG
     LIBGSL: libgsl27
 
 weekly-clang:
@@ -107,47 +96,47 @@
     CLANG: 10
     MODE: optimized
 
-# CLANG 16
-weekly-build-clang-16-debug:
-  extends: .weekly-clang-ubuntu23.04
+# CLANG 18
+weekly-build-clang-18-debug:
+  extends: .weekly-clang-ubuntu24.04
   needs: ["weekly-clang"]
   stage: build
   variables:
-    CLANG: 16
+    CLANG: 18
     MODE: debug
 
-weekly-build-clang-16-default:
-  extends: .weekly-clang-ubuntu23.04
+weekly-build-clang-18-default:
+  extends: .weekly-clang-ubuntu24.04
   needs: ["weekly-clang"]
   stage: build
   variables:
-    CLANG: 16
+    CLANG: 18
     MODE: default
 
-weekly-build-clang-16-optimized:
-  extends: .weekly-clang-ubuntu23.04
+weekly-build-clang-18-optimized:
+  extends: .weekly-clang-ubuntu24.04
   needs: ["weekly-clang"]
   stage: build
   variables:
-    CLANG: 16
+    CLANG: 18
     MODE: optimized
 
-weekly-test-clang-16-default:
-  extends: .weekly-clang-ubuntu23.04
+weekly-test-clang-18-default:
+  extends: .weekly-clang-ubuntu24.04
   stage: test
-  needs: ["weekly-build-clang-16-default"]
+  needs: ["weekly-build-clang-18-default"]
   dependencies:
-    - weekly-build-clang-16-default
+    - weekly-build-clang-18-default
   variables:
-    CLANG: 16
+    CLANG: 18
     MODE: default
 
-weekly-test-clang-16-optimized:
-  extends: .weekly-clang-ubuntu23.04
+weekly-test-clang-18-optimized:
+  extends: .weekly-clang-ubuntu24.04
   stage: test
-  needs: ["weekly-build-clang-16-optimized"]
+  needs: ["weekly-build-clang-18-optimized"]
   dependencies:
-    - weekly-build-clang-16-optimized
+    - weekly-build-clang-18-optimized
   variables:
-    CLANG: 16
+    CLANG: 18
     MODE: optimized
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-code-linting.yml ns-3.42/utils/tests/gitlab-ci-code-linting.yml
--- ns-3.41/utils/tests/gitlab-ci-code-linting.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-code-linting.yml	2024-05-29 15:29:47.228073800 -0700
@@ -14,6 +14,7 @@
   script:
     - python3 utils/check-style-clang-format.py --verbose .
   timeout: 1h
+  interruptible: true
 
 check-style-clang-format-17:
   extends: .check-style-clang-format
@@ -103,6 +104,7 @@
       exit 0 ;
       fi
   timeout: 1h
+  interruptible: true
 
 # Spell checking
 spell-check:
@@ -121,6 +123,7 @@
     # Check source code and commit messages
     - codespell -f -C0 ./
   timeout: 1h
+  interruptible: true
 
 # Check cmake format
 cmake-format:
@@ -132,6 +135,7 @@
     - ./ns3 configure --enable-modules=core
     - ./ns3 build cmake-format-check
   timeout: 1h
+  interruptible: true
 
 # Check Python format
 .python-format:
@@ -142,6 +146,7 @@
     - black --check .
     - isort --check .
   timeout: 1h
+  interruptible: true
 
 python-format-latest:
   extends: .python-format
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-cppyy.yml ns-3.42/utils/tests/gitlab-ci-cppyy.yml
--- ns-3.41/utils/tests/gitlab-ci-cppyy.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-cppyy.yml	2024-05-29 15:29:47.228073800 -0700
@@ -1,8 +1,6 @@
 cppyy-22.04:
   stage: test
   image: ubuntu:22.04 # python 3.10
-  rules:
-    - if: $RELEASE == "manual"
   dependencies: []
   before_script:
     - apt update
@@ -11,7 +9,7 @@
       python3 python3-pip
       libboost-dev libgsl-dev libgtk-3-dev
       git wget
-    - pip install cppyy==2.4.2 matplotlib numpy
+    - pip install cppyy==3.1.2 matplotlib numpy
   script:
     - ./ns3 configure -G Ninja --enable-python-bindings
     - ./ns3 build
@@ -42,7 +40,7 @@
       python3 python3-pip
       libboost-dev libgsl-dev libgtk-3-dev
       git wget
-    - pip install cppyy==2.4.2
+    - pip install cppyy==3.1.2
   script:
     - ./ns3 configure -G Ninja --enable-python-bindings
     - ./ns3 build
@@ -69,7 +67,7 @@
     # Upgrade the pip version to reuse the pre-build cppyy
     - python -m pip install pip --upgrade
     - python -m pip install setuptools setuptools_scm wheel --upgrade
-    - python -m pip install auditwheel cmake-build-extension cppyy==2.4.2
+    - python -m pip install auditwheel cmake-build-extension cppyy==3.1.2
     # Configure and build wheel
     - python setup.py bdist_wheel build_ext
     - export EXCLUDE_INTERNAL_LIBRARIES=`python ./build-support/pip-wheel/auditwheel-exclude-list.py`
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-doc.yml ns-3.42/utils/tests/gitlab-ci-doc.yml
--- ns-3.41/utils/tests/gitlab-ci-doc.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-doc.yml	2024-05-29 15:29:47.228073800 -0700
@@ -69,62 +69,37 @@
   #   - nsnam
   #   - linux
 
-manual:
+.sphinx-doc:
   extends: .doc
   script:
-    # - mkdir -p public/manual
-    - cd doc/manual
+    # - mkdir -p public/$DOC_DIR
+    - cd doc/$DOC_DIR
     - make html
     - make latexpdf
-    # - mv build/html ../../public/manual
-    # - mv build/latex/ns-3-manual.pdf ../../public/
-  # only:
-  #   - master
+    # - mv build/html ../../public/$DOC_DIR
+    # - mv build/latex/ns-3-$DOC_DIR.pdf ../../public/
+
+manual:
+  extends: .sphinx-doc
+  variables:
+    DOC_DIR: manual
 
 tutorial:
-  extends: .doc
-  script:
-    # - mkdir -p public/manual
-    - cd doc/tutorial
-    - make html
-    - make latexpdf
-    # - mv build/html ../../public/manual
-    # - mv build/latex/ns-3-tutorial.pdf ../../public/
-  # only:
-  #   - master
+  extends: .sphinx-doc
+  variables:
+    DOC_DIR: tutorial
 
 models:
-  extends: .doc
-  script:
-    # - mkdir -p public/models
-    - cd doc/models
-    - make html
-    - make latexpdf
-    # - mv build/html ../../public/models
-    # - mv build/latex/ns-3-model-library.pdf ../../public
-  # only:
-  #   - master
+  extends: .sphinx-doc
+  variables:
+    DOC_DIR: models
 
 contributing:
-  extends: .doc
-  script:
-    # - mkdir -p public/contributing
-    - cd doc/contributing
-    - make html
-    - make latexpdf
-    # - mv build/html ../../public/manual
-    # - mv build/latex/ns-3-manual.pdf ../../public/
-  # only:
-  #   - master
+  extends: .sphinx-doc
+  variables:
+    DOC_DIR: contributing
 
 installation:
-  extends: .doc
-  script:
-    # - mkdir -p public/installation
-    - cd doc/installation
-    - make html
-    - make latexpdf
-    # - mv build/html ../../public/manual
-    # - mv build/latex/ns-3-manual.pdf ../../public/
-  # only:
-  #   - master
+  extends: .sphinx-doc
+  variables:
+    DOC_DIR: installation
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-per-commit.yml ns-3.42/utils/tests/gitlab-ci-per-commit.yml
--- ns-3.41/utils/tests/gitlab-ci-per-commit.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-per-commit.yml	2024-05-29 15:29:47.228073800 -0700
@@ -8,23 +8,23 @@
       - $CPPYY == "True"
       - $RELEASE == "weekly"
       - $RELEASE == "daily"
-  interruptible: true
   image: archlinux
   before_script:
     - pacman-key --init
     - pacman -Syu --noconfirm
-      base-devel gcc clang cmake ninja ccache
+      base-devel gcc clang libc++ cmake ninja ccache
       python
       boost gsl gtk3 openmpi
       openssh
 
 # Build stage
-per-commit-clang-debug:
+per-commit-clang-optimized-libc++:
   extends: .base-per-commit-compile
   stage: build
   variables:
-    MODE: debug
+    MODE: optimized
     COMPILER: clang++
+    CXXFLAGS: -stdlib=libc++
 
 per-commit-gcc-debug:
   extends: .base-per-commit-compile
@@ -55,13 +55,13 @@
     COMPILER: g++
     EXTRA_OPTIONS: --disable-precompiled-headers
 
-per-commit-disabled-asserts:
+per-commit-clang-disabled-asserts-logs:
   extends: .base-per-commit-compile
   stage: build
   variables:
     MODE: debug
-    COMPILER: g++
-    EXTRA_OPTIONS: --disable-asserts
+    COMPILER: clang++
+    EXTRA_OPTIONS: --disable-asserts --disable-logs
 
 # Test stage
 per-commit-gcc-default-test:
@@ -83,3 +83,14 @@
   variables:
     MODE: optimized
     COMPILER: g++
+
+per-commit-clang-optimized-libc++-test:
+  extends: .base-per-commit-compile
+  stage: test
+  needs: ["per-commit-clang-optimized-libc++"]
+  dependencies:
+    - per-commit-clang-optimized-libc++
+  variables:
+    MODE: optimized
+    COMPILER: clang++
+    CXXFLAGS: -stdlib=libc++
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-release.yml ns-3.42/utils/tests/gitlab-ci-release.yml
--- ns-3.41/utils/tests/gitlab-ci-release.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-release.yml	2024-05-29 15:29:47.228073800 -0700
@@ -20,6 +20,6 @@
         - name: Official Releases (nsnam.org)
           url: https://www.nsnam.org/releases/
         - name: RELEASE_NOTES.md
-          url: $CI_PROJECT_URL/-/blob/$CI_DEFAULT_BRANCH/RELEASE_NOTES.md
+          url: $CI_PROJECT_URL/-/blob/$CI_COMMIT_TAG/RELEASE_NOTES.md
         - name: CHANGES.md
-          url: $CI_PROJECT_URL/-/blob/$CI_DEFAULT_BRANCH/CHANGES.md
+          url: $CI_PROJECT_URL/-/blob/$CI_COMMIT_TAG/CHANGES.md
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci-scheduled.yml ns-3.42/utils/tests/gitlab-ci-scheduled.yml
--- ns-3.41/utils/tests/gitlab-ci-scheduled.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci-scheduled.yml	2024-05-29 15:29:47.228073800 -0700
@@ -23,7 +23,7 @@
     - export CCACHE_DIR=${PWD}/$CCACHE_BASEDIR_VALUE
     - export MPI_CI=1
     # missing the flag --disable-python
-    - ./ns3 configure -d $MODE -GNinja --enable-examples --enable-tests --enable-mpi --disable-gtk
+    - ./ns3 configure -d $MODE -GNinja --enable-examples --enable-tests --enable-mpi --disable-gtk $EXTRA_OPTIONS
     - if [[ "$CI_JOB_STAGE" == "build" ]];
       then ./ns3 build;
       fi
@@ -41,6 +41,7 @@
     FULLNESS: ""
     # workaround for Valgrind on Archlinux https://bbs.archlinux.org/viewtopic.php?pid=2036171#p2036171
     DEBUGINFOD_URLS: "https://debuginfod.archlinux.org"
+  interruptible: true
 
 daily-jobs:
   rules:
@@ -128,6 +129,24 @@
   variables:
     MODE: optimized
 
+### Sanitizer tests
+weekly-build-test-optimized-sanitizers:
+  extends: .base-test
+  rules:
+    - if: $RELEASE == "weekly"
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+      allow_failure: true
+  stage: build
+  needs: ["weekly-slow-jobs"]
+  dependencies: []
+  variables:
+    MODE: optimized
+    EXTRA_OPTIONS: --enable-sanitizers --disable-mpi
+    FORCE_TESTS: Force
+  tags:
+    - nsnam
+    - linux
+
 ### Valgrind tests
 # Run the test.py script with files compiled in optimized mode + valgrind (daily)
 daily-build-test-optimized-valgrind:
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/gitlab-ci.yml ns-3.42/utils/tests/gitlab-ci.yml
--- ns-3.41/utils/tests/gitlab-ci.yml	2024-02-09 14:44:08.629795300 -0800
+++ ns-3.42/utils/tests/gitlab-ci.yml	2024-05-29 15:29:47.228073800 -0700
@@ -26,11 +26,16 @@
   - release
 
 workflow:
+  auto_cancel:
+    on_new_commit: interruptible
   rules:
+    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+      auto_cancel:
+        on_new_commit: none
     - if: $CI_PIPELINE_SOURCE == "merge_request_event"
     - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
       when: never
-    - if: $CI_COMMIT_BRANCH
+    - when: always
 
 ###################### BUILD STAGE #############################################
 
@@ -73,6 +78,7 @@
     key: "ccache-$CI_JOB_NAME"
     paths:
       - $CCACHE_BASEDIR_VALUE/
+  interruptible: true
   timeout: 12h
   variables:
     CCACHE_BASEDIR_VALUE: ns-3-ccache-storage
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/utils/tests/test-ns3.py ns-3.42/utils/tests/test-ns3.py
--- ns-3.41/utils/tests/test-ns3.py	2024-02-09 14:44:08.633795300 -0800
+++ ns-3.42/utils/tests/test-ns3.py	2024-05-29 15:29:47.228073800 -0700
@@ -1064,7 +1064,10 @@
                 f.write(ns3rc_template.format(modules="'lte'", examples="False", tests="True"))
 
             # Reconfigure.
-            return_code, stdout, stderr = run_ns3('configure -G "{generator}"')
+            run_ns3("clean")
+            return_code, stdout, stderr = run_ns3(
+                'configure -G "{generator}" -d release --enable-verbose'
+            )
             self.config_ok(return_code, stdout, stderr)
 
             # Check.
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/VERSION ns-3.42/VERSION
--- ns-3.41/VERSION	2024-02-09 14:45:45.430484000 -0800
+++ ns-3.42/VERSION	2024-05-29 15:30:03.724115800 -0700
@@ -1 +1 @@
-3.41
+3.42
diff -Naur -x '*.dia' -x '*.pcap' -x '*.png' ns-3.41/.vscode/tasks.json ns-3.42/.vscode/tasks.json
--- ns-3.41/.vscode/tasks.json	2024-02-09 14:44:07.717788700 -0800
+++ ns-3.42/.vscode/tasks.json	2024-05-29 15:29:46.824072800 -0700
@@ -22,4 +22,4 @@
             }
         }
     ]
-}
\ No newline at end of file
+}
